opendataloader-project/opendataloader-pdf · error · IOException

Hancom AI DOCUMENT_LAYOUT_WITH_OCR returned empty result — b

Error message

Hancom AI DOCUMENT_LAYOUT_WITH_OCR returned empty result — backend unavailable or rejected the document

What it means

The first Hancom AI pipeline step, DOCUMENT_LAYOUT_WITH_OCR, returned null, a non-array, or an empty array. Because every later step (TSR, figure captioning) depends on DLA+OCR output, an empty result is treated as a hard failure so the caller can fall back to the Java pipeline instead of silently emitting an empty document.

Source

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

        LOGGER.log(Level.INFO, "Hancom AI: processing PDF ({0} bytes)", pdfBytes.length);

        // Crop / page-image destination travels with the request, not the
        // cached client's config, so the per-document target is correct even
        // when the client is reused across documents (and is concurrency-safe
        // since nothing shared is mutated).
        CropOutput cropOutput = request.getCropOutput();

        try (PageImageCache pageImageCache = createPageImageCache()) {
            ObjectNode merged = objectMapper.createObjectNode();
            ObjectNode timingsNode = objectMapper.createObjectNode();

            // Step 1: DLA + OCR. This is required — downstream steps have nothing
            // to process without it, so treat an empty response as a failure so the
            // caller can fall back to the Java pipeline instead of silently emitting
            // an empty document.
            JsonNode dlaOcrResult = callModule(pdfBytes, "DOCUMENT_LAYOUT_WITH_OCR");
            if (dlaOcrResult == null || !dlaOcrResult.isArray() || dlaOcrResult.size() == 0) {
                throw new IOException(
                    "Hancom AI DOCUMENT_LAYOUT_WITH_OCR returned empty result — "
                    + "backend unavailable or rejected the document");
            }
            merged.set("DOCUMENT_LAYOUT_WITH_OCR", dlaOcrResult);
            addTimings(timingsNode, "DOCUMENT_LAYOUT_WITH_OCR", dlaOcrResult);

            // Step 2: Table Structure — crop each Table region from page image, send to TSR individually
            long tsrStartMs = System.currentTimeMillis();
            ArrayNode tsrResults = recognizeTableStructures(pdfBytes, dlaOcrResult, pageImageCache, cropOutput);
            long tsrMs = System.currentTimeMillis() - tsrStartMs;
            merged.set("TABLE_STRUCTURE_RECOGNITION", tsrResults);

            ObjectNode tsrTiming = objectMapper.createObjectNode();
            tsrTiming.put("total_ms", tsrMs);
            tsrTiming.put("count", tsrResults.size());
            if (tsrResults.size() > 0) {
                tsrTiming.put("avg_ms", tsrMs / tsrResults.size());
            }

View on GitHub (pinned to a7789b8e77)

Solutions

  1. Check the server logs for the DOCUMENT_LAYOUT_WITH_OCR failure reason (callModule logs the MSG at WARNING)
  2. Retry once in case of transient backend unavailability
  3. Decrypt or repair the PDF before sending
  4. Fall back to Java-only processing for this document (--hybrid-fallback)
  5. Restart the Hancom AI backend if its model crashed
Defensive patterns

Strategy: fallback

Try / catch

try {
    return client.convert(request);
} catch (IOException e) {
    if (e.getMessage().contains("DOCUMENT_LAYOUT_WITH_OCR returned empty result")) {
        // backend rejected the doc — fall back to Java pipeline
        log.warn("DLA+OCR empty, falling back to Java-only");
        return null;
    }
    throw e;
}

Prevention

When it happens

Trigger: callModule(pdfBytes, "DOCUMENT_LAYOUT_WITH_OCR") returns null, a non-array JsonNode, or a zero-length array (the backend returned SUCCESS=false or an empty RESULT, which callModule collapses to an empty array).

Common situations: Backend model not loaded / crashed; backend rejected the PDF (corrupt, encrypted, unsupported); backend returned SUCCESS=false with a MSG that callModule only logged at WARNING; backend resource exhaustion.

Related errors


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