Java ImageIO.read returns null on a Sume WebP: request PNG

ImageIO.read gives null when no reader claims the stream. Check the reader list, then pin output_format to png or jpeg on a Sume /v1/images call.

4 min readSume
All posts

ImageIO.read returns null, not an exception, when no registered reader recognises the bytes. Oracle's ImageIO documentation says exactly that, and it also gives getReaderFormatNames() to list what your runtime can decode. So a downloaded Sume image that comes back null is usually a WebP that your JDK has no reader plugin for. Whether WebP is on your list depends on the JDK and any plugins on the classpath, so print the list instead of assuming.

The fix on the Sume side is one field. The image API docs list output_format as png, jpeg or webp, and the catalog restricts it per model. Recraft V4 is the exception: its catalog row lists only webp, so a Java client that must read Recraft output needs a WebP reader or a different model.

How do I tell a null from a bad download?

Separate the two failures. A failed or truncated download throws an IOException or leaves you with an empty byte array. A complete download of a format with no reader gives null. Check the bytes first, then the null.

Every /v1/images response carries data[].media_type, for example image/webp, next to data[].url. Log it. If it says image/webp and your reader list lacks webp, you have found the cause without a debugger.

A single-file check you can run

Save this as ReadSume.java and run java ReadSume.java <image-url> on JDK 11 or later, passing the data[0].url from a Sume response. It downloads the bytes, tries ImageIO.read, and prints either the size or the registered readers.

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import javax.imageio.ImageIO;

public class ReadSume {
  public static void main(String[] args) throws Exception {
    HttpClient http = HttpClient.newHttpClient();
    HttpRequest get = HttpRequest.newBuilder(URI.create(args[0])).build();
    byte[] bytes = http.send(get, HttpResponse.BodyHandlers.ofByteArray()).body();
    BufferedImage img = ImageIO.read(new ByteArrayInputStream(bytes));
    if (img == null) {
      System.out.println("No reader claimed " + bytes.length + " bytes. Registered: "
          + String.join(", ", ImageIO.getReaderFormatNames()));
      return;
    }
    System.out.println(img.getWidth() + "x" + img.getHeight());
  }
}

Ask for a format Java reads

Send output_format in the request body so the decision is yours and not the model default. png is lossless and fine for graphics; jpeg is smaller for photos. Both are accepted by every catalog model except Recraft V4. If a model does not list the parameter you send, the API answers 400 unsupported_parameter instead of ignoring it, so a wrong value fails loudly.

A body that works for the Java check above:

{
  "model": "openai/gpt-image-2.5",
  "prompt": "a red kettle on a white table, studio light",
  "quality": "low",
  "output_format": "png"
}

Do not forget the 202 path

POST /v1/images waits up to 30 seconds and returns 200 with the image body. If the job needs longer, you get 202 and a job envelope with status_url and result_url, and the image comes from the standard job result, not from the response. Branch on HttpResponse.statusCode() before you touch data[0].url. The jobs guide says to poll with backoff and never to resubmit a paid request because a local timeout fired.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume