opendataloader-project/opendataloader-pdf · error · IOException

No ImageIO writer accepted PNG output for page %s

Error message

No ImageIO writer accepted PNG output for page %s

What it means

After fetching a page image, DiskPageImageCache persists it with ImageIO.write(image, "png", file). ImageIO.write returns false when no registered ImageWriter accepts the PNG format for that image type, which the cache treats as a fatal IOException because caching would silently produce nothing. It indicates the PNG writer plugin is unavailable in the runtime JRE.

Source

Thrown at java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/DiskPageImageCache.java:64

    @Override
    public BufferedImage getOrFetch(int pageIndex, PageImageFetcher fetcher) throws IOException {
        Path file = tempDir.resolve("page-" + pageIndex + ".png");
        if (Files.exists(file)) {
            BufferedImage cached = ImageIO.read(file.toFile());
            if (cached != null) {
                return cached;
            }
            // Cached file is unreadable (corrupt or no ImageReader) — re-fetch.
            LOGGER.log(Level.WARNING, "Cached page image is unreadable, re-fetching: {0}", file);
            Files.deleteIfExists(file);
        }
        BufferedImage image = fetcher.fetch(pageIndex);
        if (image == null) {
            throw new IOException("Page image fetcher returned null for page " + pageIndex);
        }
        if (!ImageIO.write(image, "png", file.toFile())) {
            throw new IOException("No ImageIO writer accepted PNG output for page " + pageIndex);
        }
        return image;
    }

    @Override
    public void evict(int pageIndex) {
        // no-op: keep on disk for potential re-read
    }

    @Override
    public void close() throws IOException {
        if (!Files.exists(tempDir)) {
            return;
        }
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(tempDir)) {
            for (Path entry : stream) {
                try {
                    Files.deleteIfExists(entry);

View on GitHub (pinned to a7789b8e77)

Solutions

  1. Use a full JRE/JDK distribution (not a jlink-stripped runtime) so com.sun.imageio.plugins.png is present
  2. Verify PNG support at startup: ImageIO.getImageWritersByFormatName("png").hasNext()
  3. If packaging with jlink, include the java.desktop module
  4. Check for dependency shading that relocates/excludes imageio service files under META-INF/services
Defensive patterns

Strategy: validation

Validate before calling

// Verify PNG write support once at startup
boolean pngOk = javax.imageio.ImageIO.getImageWritersByFormatName("png").hasNext();
if (!pngOk) {
    throw new IllegalStateException(
        "No ImageIO PNG writer registered — use a full JRE/JDK, not a stripped runtime");
}

Try / catch

try {
    return cache.getOrFetch(pageIndex, fetcher);
} catch (IOException e) {
    if (e.getMessage().contains("No ImageIO writer accepted PNG")) {
        LOG.error("PNG ImageIO plugin missing from JRE — install java.desktop / full JDK", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: ImageIO.write returns false for the 'png' format — i.e. no ImageIO service provider for PNG is registered, or the BufferedImage type is one no writer will accept. The page index is included in the message.

Common situations: Running on a stripped/headless JRE or a minimal container image that omits the javax.imageio PNG plugins; shading/dependency conflicts that drop imageio plugins; custom BufferedImage subtypes with an unusual color model.

Related errors


AI-assisted analysis of opendataloader-project/opendataloader-pdf@a7789b8e77 (2026-08-14). Data as JSON: /api/errors/65c869bc1c135c33. Report an issue: GitHub.