opendataloader-project/opendataloader-pdf · error · IOException

pdf2img returned empty body

Error message

pdf2img returned empty body

What it means

The pdf2img endpoint returned 2xx but response.body() was null, so there is no JSON to parse for the page image. Like error 47 this points to a transport/proxy artifact rather than a content problem. It is a per-page IOException caught and logged by the table/figure handlers.

Source

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

                "odl-" + sourcePdfShaShort + "-pdf2img-p" + pageIndex)
            .addFormDataPart("PAGE_INDEX", String.valueOf(pageIndex))
            .addFormDataPart("FILE", DEFAULT_FILENAME,
                RequestBody.create(pdfBytes, MEDIA_TYPE_PDF))
            .build();

        Request httpRequest = new Request.Builder()
            .url(baseUrl + PDF2IMG_ENDPOINT)
            .post(body)
            .build();

        try (Response response = httpClient.newCall(httpRequest).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("pdf2img returned HTTP " + response.code());
            }

            ResponseBody respBody = response.body();
            if (respBody == null) {
                throw new IOException("pdf2img returned empty body");
            }

            JsonNode root = objectMapper.readTree(respBody.string());
            // Navigate: RESULT[0].RESULT.PAGE_PNG_DATA
            JsonNode resultArr = root.get("RESULT");
            if (resultArr == null || !resultArr.isArray() || resultArr.size() == 0) {
                throw new IOException("pdf2img RESULT is empty");
            }

            JsonNode pageResult = resultArr.get(0);
            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()) {

View on GitHub (pinned to a7789b8e77)

Solutions

  1. Hit the backend pdf2img endpoint directly, bypassing proxies
  2. Confirm the backend returns 200 with a JSON body for pdf2img
  3. Retry the page render; transient null bodies are often connection artifacts
  4. Accept the per-page skip if it affects only some pages
Defensive patterns

Strategy: try-catch

Try / catch

try {
    return cache.getOrFetch(pageNum, idx -> client.fetchPageImage(pdf, idx, crop));
} catch (IOException e) {
    if ("pdf2img returned empty body".equals(e.getMessage())) {
        // retry once — often a proxy/connection artifact
        return cache.getOrFetch(pageNum, idx -> client.fetchPageImage(pdf, idx, crop));
    }
    log.warn("skipping page {}: {}", pageNum, e.getMessage());
    continue;
}

Prevention

When it happens

Trigger: POST to /support/pdf2img returns 2xx with a null ResponseBody inside fetchPageImage.

Common situations: A proxy/gateway between client and backend that strips or empties the body on the page render response; backend returning 204 by mistake; connection reuse closing the stream early.

Related errors


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