{"record":{"id":"91e3f86c1e72f998","repo":"opendataloader-project/opendataloader-pdf","slug":"backend-processing-failed-and-fallback-is-disabled","errorCode":null,"errorMessage":"Backend processing failed and fallback is disabled","messagePattern":"Backend processing failed and fallback is disabled","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/processors/HybridDocumentProcessor.java","lineNumber":334,"sourceCode":"        // Process backend path (synchronous)\n        Map<Integer, List<IObject>> backendResults;\n        Set<Integer> backendFailedPages = new HashSet<>();\n        // Track SemanticPicture→EnrichedImageChunk swaps so we can rekey\n        // ElementMetadata after Phase 6 cross-page processors (HeaderFooter,\n        // List, etc.) re-run setIDs and mutate the picture's structure id.\n        Map<EnrichedImageChunk, Long> pictureSwapOriginalIds = new IdentityHashMap<>();\n        try {\n            backendResults = processBackendPath(inputPdfName, backendPages, config, backendFailedPages);\n            // Enrich backend results: copy StreamInfos from Java-extracted content for MCID linkage\n            enrichBackendResults(backendResults, filteredContents, config.getHybridConfig(),\n                pictureSwapOriginalIds);\n        } catch (Exception e) {\n            LOGGER.log(Level.WARNING, \"Backend processing failed: {0}\", e.getMessage());\n            if (config.getHybridConfig().isFallbackToJava()) {\n                LOGGER.log(Level.INFO, \"Falling back to Java processing for backend pages\");\n                backendResults = processJavaPath(filteredContents, backendPages, config, totalPages);\n            } else {\n                throw new IOException(\"Backend processing failed and fallback is disabled\", e);\n            }\n        }\n\n        // Fallback: reprocess backend-failed pages through Java path\n        if (!backendFailedPages.isEmpty()) {\n            // Log 1-indexed page numbers for human readability\n            List<Integer> failedPages1Indexed = backendFailedPages.stream()\n                .map(p -> p + 1).sorted().collect(Collectors.toList());\n            if (config.getHybridConfig().isFallbackToJava()) {\n                LOGGER.log(Level.WARNING, \"Backend returned partial_success: {0} page(s) failed (pages {1}), falling back to Java path\",\n                    new Object[]{backendFailedPages.size(), failedPages1Indexed});\n                Map<Integer, List<IObject>> fallbackResults = processJavaPath(\n                    filteredContents, backendFailedPages, config, totalPages\n                );\n                backendResults.putAll(fallbackResults);\n            } else {\n                LOGGER.log(Level.WARNING, \"Backend returned partial_success: {0} page(s) failed (pages {1}), fallback disabled — failing fast\",\n                    new Object[]{backendFailedPages.size(), failedPages1Indexed});","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/opendataloader-project/opendataloader-pdf/blob/a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8/java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/processors/HybridDocumentProcessor.java#L316-L352","documentation":"IOException thrown from the hybrid backend path when processBackendPath throws for the ENTIRE backend batch (not a per-page partial_success) AND config.getHybridConfig().isFallbackToJava() is false. The backend exception is wrapped as the cause. This is the whole-backend failure mode; contrast error 85 which handles per-page partial failures. The library first logs the backend failure at WARNING, then either falls back to Java (if enabled) or rethrows this.","triggerScenarios":"Running HybridDocumentProcessor with hybrid enabled, backend pages routed, and processBackendPath(inputPdfName, backendPages, config, backendFailedPages) throws (backend server unreachable, returns non-2xx, connection reset, deserialization error) while config.getHybridConfig().isFallbackToJava() == false.","commonSituations":"Hybrid backend server is down or the hybrid_url is wrong/misconfigured and the operator explicitly disabled fallback (--hybrid-fallback off) for strict backend-only operation. TLS/cert mismatch with the backend. Backend out of memory. Network partition between client and backend.","solutions":["Enable fallback if partial Java output is acceptable: set config.getHybridConfig().setFallbackToJava(true) / pass --hybrid-fallback so backend pages fall back to the Java path instead of failing.","Diagnose the backend: read getCause() for the HTTP/connection error and verify the backend server is up and reachable at the configured hybrid_url.","If strict backend-only is intentional, treat this as a hard failure — fix/restart the backend, then retry.","Confirm hybrid_url is correct and resolvable from the client host, and that the backend health endpoint responds."],"exampleFix":"// before: fallback disabled, whole backend down -> hard fail\nconfig.getHybridConfig().setFallbackToJava(false);\n// after: tolerate backend outage by falling back to Java\nconfig.getHybridConfig().setFallbackToJava(true);","handlingStrategy":"fallback","validationCode":"// Before processing, decide fallback policy and check backend reachability:\nif (config.getHybridConfig() != null && config.getHybridConfig().isHybridEnabled()\n        && !config.getHybridConfig().isFallbackToJava()) {\n    if (!isBackendReachable(config.getHybridConfig().getBackendUrl())) {\n        throw new IllegalStateException(\"Backend unreachable and fallback disabled\");\n    }\n}","typeGuard":"static boolean isBackendFailedNoFallback(IOException e) {\n    return e.getMessage() != null\n        && e.getMessage().equals(\"Backend processing failed and fallback is disabled\");\n}","tryCatchPattern":"try {\n    HybridDocumentProcessor.process(inputPdfName, config);\n} catch (IOException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Backend processing failed and fallback is disabled\")) {\n        log.error(\"Backend down, fallback off\", e.getCause());\n        // Either enable fallback and retry, or surface to the user.\n        config.getHybridConfig().setFallbackToJava(true);\n        HybridDocumentProcessor.process(inputPdfName, config);\n    } else throw e;\n}","preventionTips":["Enable --hybrid-fallback unless strict backend-only semantics are mandatory.","Health-check the backend URL before submitting the batch.","Log getCause() to distinguish connectivity errors from backend crashes."],"tags":["hybrid","backend","fallback","network","ioexception"],"backgroundTag":null,"analyzedSha":"a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8","analyzedAt":"2026-08-14T05:22:03.953Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}