opendataloader-project/opendataloader-pdf · error · IOException

Hancom visualinfo failed with status %s: %s

Error message

Hancom visualinfo failed with status %s: %s

What it means

The Hancom visualinfo endpoint (GET with fileId, dlaMode, and ocrMode parameters) returned an HTTP status outside the 2xx range. The error includes the status code and raw response body. This call happens after a successful upload, so it indicates the server accepted the file but cannot or will not process it for visual info extraction.

Source

Thrown at java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/HancomClient.java:238

     * @return The visual info JSON response.
     * @throws IOException If the request fails.
     */
    private JsonNode getVisualInfo(String fileId) throws IOException {
        String url = baseUrl + String.format(VISUALINFO_ENDPOINT, fileId) +
            "?engine=" + ENGINE +
            "&dlaMode=" + DLA_MODE +
            "&ocrMode=" + OCR_MODE;

        Request request = new Request.Builder()
            .url(url)
            .get()
            .build();

        try (Response response = httpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                ResponseBody body = response.body();
                String bodyStr = body != null ? body.string() : "";
                throw new IOException("Hancom visualinfo failed with status " + response.code() + ": " + bodyStr);
            }

            ResponseBody body = response.body();
            if (body == null) {
                throw new IOException("Empty response body from visualinfo");
            }

            return objectMapper.readTree(body.string());
        }
    }

    /**
     * Deletes an uploaded file from the server.
     *
     * <p>This method silently ignores any errors to ensure cleanup
     * doesn't interfere with the main processing result.
     *
     * @param fileId The file ID to delete.

View on GitHub (pinned to a7789b8e77)

Solutions

  1. Inspect the response body in the error message for the server's failure reason code.
  2. For 404: the fileId may have expired — re-upload the PDF and immediately call getVisualInfo.
  3. For 408/504: the PDF may be too large/complex — try splitting it or reducing page count.
  4. For 5xx: retry with backoff — transient server-side processing failures are common under load.
  5. Verify the uploaded file is a valid, unencrypted PDF using `qpdf --check doc.pdf` or `java -jar pdfbox-app.jar PDFParser doc.pdf`.
  6. Check that DLA_MODE and OCR_MODE constants match the server's expected parameter values.

Example fix

// before: no retry, transient 5xx failures abort the conversion
JsonNode visualInfo = client.getVisualInfo(fileId);

// after: retry visualinfo with backoff for transient server errors
JsonNode visualInfo = null;
for (int attempt = 0; attempt < 3; attempt++) {
    try {
        visualInfo = client.getVisualInfo(fileId);
        break;
    } catch (IOException e) {
        if (!e.getMessage().contains("status 5") || attempt == 2) throw e;
        Thread.sleep((1L << attempt) * 1000);
    }
}
Defensive patterns

Strategy: retry

Validate before calling

// Validate fileId format before calling getVisualInfo
if (fileId == null || fileId.isEmpty()) {
    throw new IllegalStateException("fileId is null or empty — upload may have failed silently");
}
// Cannot pre-validate that the server will accept the fileId.

Try / catch

try {
    JsonNode visualInfo = client.getVisualInfo(fileId);
} catch (IOException e) {
    String msg = e.getMessage();
    if (msg.contains("status 404")) {
        // fileId expired — re-upload and retry
        fileId = client.uploadFile(pdfBytes);
        visualInfo = client.getVisualInfo(fileId);
    } else if (msg.contains("status 5") || msg.contains("status 429")) {
        // Transient — retry with backoff
        Thread.sleep(2000);
        visualInfo = client.getVisualInfo(fileId);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling HancomClient.getVisualInfo(fileId) after uploadFile() succeeded. Specific triggers: 404 (fileId not found — file was already deleted or expired), 408/504 (server-side processing timeout for a very large or complex PDF), 422 (server cannot parse the PDF's visual structure), 500/502/503 (internal error during visual info extraction), 401/403 (auth token expired between upload and visualinfo calls).

Common situations: Large multi-page PDFs that take too long for the server to process within its internal timeout; the fileId expired between upload and visualinfo due to server-side TTL; server restart cleared uploaded files from its in-memory store; the uploaded PDF contains elements the visualinfo engine cannot handle (corrupt XObjects, encrypted streams, exotic color spaces).

Related errors


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