opendataloader-project/opendataloader-pdf · error · IOException

pdf2img PAGE_PNG_DATA is not valid Base64

Error message

pdf2img PAGE_PNG_DATA is not valid Base64

What it means

PAGE_PNG_DATA was present and non-empty but failed Base64 decoding (IllegalArgumentException). fetchPageImage wraps the IAE as IOException with a clear message, because the method signature only declares IOException and an escaping IAE would abort the entire conversion instead of just skipping the page. Indicates the payload is not valid Base64 (truncated, corrupted, or wrong encoding).

Source

Thrown at java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/HancomAIClient.java:722

            JsonNode innerResult = pageResult.get("RESULT");
            if (innerResult == null) {
                throw new IOException("pdf2img inner RESULT is null");
            }

            String pngBase64 = innerResult.has("PAGE_PNG_DATA")
                ? innerResult.get("PAGE_PNG_DATA").asText() : null;
            if (pngBase64 == null || pngBase64.isEmpty()) {
                throw new IOException("pdf2img PAGE_PNG_DATA is empty");
            }

            byte[] pngBytes;
            try {
                pngBytes = Base64.getDecoder().decode(pngBase64);
            } catch (IllegalArgumentException e) {
                // fetchPageImage is declared to throw IOException and callers catch
                // only IOException. Escaping IAE would abort the whole conversion
                // instead of skipping the failed page.
                throw new IOException("pdf2img PAGE_PNG_DATA is not valid Base64", e);
            }
            BufferedImage image = ImageIO.read(new ByteArrayInputStream(pngBytes));
            if (image == null) {
                throw new IOException("pdf2img PAGE_PNG_DATA is not a readable image");
            }
            if (cropOutput.active()) {
                savePageImageFile(cropOutput.directory(), pageIndex, pngBytes);
            }
            return image;
        }
    }

    /**
     * Sends a cropped image to IMAGE_CAPTIONING and returns the caption text.
     */
    /** Image-captioning result: caption text + the model's self-reported confidence. */
    static final class CaptionResult {
        final String caption;

View on GitHub (pinned to a7789b8e77)

Solutions

  1. Check whether the backend emits standard vs URL-safe Base64 and decode accordingly
  2. Strip any 'data:image/png;base64,' prefix if the backend adds one
  3. Bypass proxies that may truncate large base64 payloads
  4. Retry the page; transient truncation often clears
  5. Log the first/last chars of pngBase64 to diagnose format
Defensive patterns

Strategy: try-catch

Try / catch

try {
    return cache.getOrFetch(pageNum, idx -> client.fetchPageImage(pdf, idx, crop));
} catch (IOException e) {
    String m = e.getMessage();
    if (m.contains("not valid Base64")) {
        // possible URL-safe Base64 or data-URI prefix; retry with a tolerant decoder
        log.warn("page {} base64 decode failed — check backend encoding", pageNum);
    }
    continue;
}

Prevention

When it happens

Trigger: Base64.getDecoder().decode(pngBase64) throws IllegalArgumentException on the PAGE_PNG_DATA string inside fetchPageImage; the catch re-throws it as IOException.

Common situations: Truncated response body from a proxy cutting large images; backend returning URL-safe Base64 while the client uses standard decoder; corrupted transfer; backend bug emitting raw bytes or a data-URI prefix.

Related errors


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