{"record":{"id":"cb321a9c94e3176b","repo":"jhy/jsoup","slug":"read-timeout","errorCode":null,"errorMessage":"Read timeout","messagePattern":"Read timeout","errorType":"exception","errorClass":"SocketTimeoutException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/jsoup/internal/ControllableInputStream.java","lineNumber":106,"sourceCode":"            // interrupted latches, because parse() may call twice\n            interrupted = true;\n            return -1;\n        }\n        if (capped && remaining <= 0) {\n            if (checkTruncated()) return -1;\n            contentLength = readPos;\n            emitProgress();\n            return -1;\n        }\n\n        if (capped && len > remaining)\n            len = remaining; // don't read more than desired, even if available\n        if (capped) buff.capRemaining(remaining);\n        else buff.uncap();\n\n        while (true) { // loop trying to read until we get some data or hit the overall timeout, if we have one\n            if (expired())\n                throw new SocketTimeoutException(\"Read timeout\");\n\n            try {\n                final int read = super.read(b, off, len);\n                if (read == -1) { // completed\n                    contentLength = readPos;\n                } else {\n                    if (capped && read > 0) {\n                        remaining -= read; // track bytes returned to the caller\n                    }\n                    // todo: use long progress values in the public API; saturate until that is available\n                    readPos = read > Integer.MAX_VALUE - readPos ? Integer.MAX_VALUE : readPos + read;\n                }\n                emitProgress();\n                return read;\n            } catch (SocketTimeoutException e) {\n                if (expired() || timeout == 0)\n                    throw e;\n            }","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/jhy/jsoup/blob/9851ac5d9c576c6888910b5a51a2362bbc978959/src/main/java/org/jsoup/internal/ControllableInputStream.java#L88-L124","documentation":"ControllableInputStream.read wraps the underlying stream with an overall deadline and optional byte cap. Before each underlying read it calls expired(); if the total elapsed time exceeds the configured timeout it throws SocketTimeoutException('Read timeout'). This means the connection produced no usable data within the overall time budget, even if individual reads were trickling in.","triggerScenarios":"Jsoup.connect(url).timeout(ms).execute()/parse() where the server is slow or stalls; reads keep returning small chunks so total elapsed time exceeds the timeout; .maxBytes caps combined with slow networks; a dead proxy accepting connections but never sending data.","commonSituations":"Fetching slow or overloaded sites; scraping through a degraded proxy or VPN; long-tail responses on mobile networks; timeout set too low for large downloads on slow links.","solutions":["Raise the timeout: Jsoup.connect(url).timeout(30000) or higher for slow hosts.","Verify the URL/host responds (curl --max-time) to distinguish slowness from outage.","Retry with backoff for transient slowness.","Check proxy/VPN and network path health if all targets time out.","Use Response with maxBytes only when needed — large caps on slow links need proportionally larger timeouts."],"exampleFix":"// before\nDocument doc = Jsoup.connect(url).timeout(1000).get();\n// after\nDocument doc = Jsoup.connect(url)\n    .timeout(30000)\n    .get();","handlingStrategy":"retry","validationCode":"long timeoutMs = connection.request().timeout();\nif (timeoutMs < 5000 && isSlowHost(url)) raise timeout before connecting;","typeGuard":null,"tryCatchPattern":"try { doc = Jsoup.connect(url).timeout(30000).get(); } catch (SocketTimeoutException e) { /* retry with backoff or fail gracefully */ }","preventionTips":["Set timeouts proportionate to expected response size and link speed.","Implement retry-with-backoff for flaky hosts.","Avoid tiny maxBytes caps on slow connections.","Test flaky endpoints with curl --max-time to baseline realistic timeouts."],"tags":["timeout","network","io","socket"],"backgroundTag":"request-timeout","analyzedSha":"9851ac5d9c576c6888910b5a51a2362bbc978959","analyzedAt":"2026-09-08T15:22:04.931Z","contentChangedAt":"2026-09-08T15:22:04.931Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}