opendataloader-project/opendataloader-pdf · error · IOException

Hybrid server at %s returned HTTP %s during health check. Th

Error message

Hybrid server at %s returned HTTP %s during health check.
The server is reachable but may be starting up or unhealthy.

What it means

The docling-fast-server health check connected and got an HTTP response, but the status code was not 2xx. This distinguishes 'unreachable' (error 43) from 'reachable but unhealthy'. The message notes the server may be starting up or in a bad state, since a running process that fails /health typically is mid-initialization or has crashed its worker.

Source

Thrown at java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/DoclingFastServerClient.java:125

            .get()
            .build();

        Response response;
        try {
            response = healthClient.newCall(healthRequest).execute();
        } catch (IOException e) {
            throw new IOException(
                "Hybrid server is not available at " + baseUrl + "\n"
                + "To start the local hybrid server:\n"
                + "  1. Install: pip install \"opendataloader-pdf[hybrid]\"\n"
                + "  2. Start:   opendataloader-pdf-hybrid --port 5002\n"
                + "To use a remote server or custom port: --hybrid-url http://host:port\n"
                + "Or pass --hybrid-fallback to fall back to Java-only output for this run.\n"
                + "Or run without --hybrid flag for Java-only processing.", e);
        }
        try (response) {
            if (!response.isSuccessful()) {
                throw new IOException(
                    "Hybrid server at " + baseUrl + " returned HTTP " + response.code()
                    + " during health check.\n"
                    + "The server is reachable but may be starting up or unhealthy.");
            }
        }
    }

    @Override
    public HybridResponse convert(HybridRequest request) throws IOException {
        Request httpRequest = buildConvertRequest(request);
        LOGGER.log(Level.FINE, "Sending request to {0}", baseUrl + CONVERT_ENDPOINT);

        try (Response response = httpClient.newCall(httpRequest).execute()) {
            return parseResponse(response);
        }
    }

    @Override

View on GitHub (pinned to a7789b8e77)

Solutions

  1. Wait for the server to finish model warm-up and retry
  2. Check the server logs for startup errors or OOM
  3. Upgrade/downgrade the server to a version whose /health returns 200 when ready
  4. Use --hybrid-fallback or drop --hybrid to proceed Java-only
Defensive patterns

Strategy: retry

Try / catch

// Retry the health check while the server warms up
for (int attempt = 1; attempt <= 5; attempt++) {
    try {
        client.checkAvailability();
        break;
    } catch (IOException e) {
        if (attempt == 5 || !e.getMessage().contains("during health check")) throw e;
        Thread.sleep(2000L * attempt);
    }}

Prevention

When it happens

Trigger: GET to baseUrl + '/health' succeeds at the TCP/HTTP level but returns a non-2xx status (e.g. 500 or 503) within the 3s health-check timeout.

Common situations: Server still loading the ML model on first request (returns 503); backend crashed but the FastAPI/liveness wrapper still answers; version mismatch between client expectations and server /health contract; resource exhaustion (OOM) making the server return 500.

Related errors


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