{"record":{"id":"054d3205f58ae339","repo":"yt-dlp/yt-dlp","slug":"partial-bytes-read-expected-more-expected","errorCode":null,"errorMessage":"{partial} bytes read, {expected} more expected","messagePattern":"(.+?) bytes read, (.+?) more expected","errorType":"exception","errorClass":"IncompleteRead","httpStatus":null,"severity":"error","filePath":"yt_dlp/networking/_requests.py","lineNumber":152,"sourceCode":"            data = self._real_read(amt)\n            if self.fp.closed:\n                self.close()\n            return data\n        # See urllib3.response.HTTPResponse.read() for exceptions raised on read\n        except urllib3.exceptions.SSLError as e:\n            raise SSLError(cause=e) from e\n\n        except urllib3.exceptions.ProtocolError as e:\n            # IncompleteRead is always contained within ProtocolError\n            # See urllib3.response.HTTPResponse._error_catcher()\n            ir_err = next(\n                (err for err in (e.__context__, e.__cause__, *variadic(e.args))\n                 if isinstance(err, http.client.IncompleteRead)), None)\n            if ir_err is not None:\n                # `urllib3.exceptions.IncompleteRead` is subclass of `http.client.IncompleteRead`\n                # but uses an `int` for its `partial` property.\n                partial = ir_err.partial if isinstance(ir_err.partial, int) else len(ir_err.partial)\n                raise IncompleteRead(partial=partial, expected=ir_err.expected) from e\n            raise TransportError(cause=e) from e\n\n        except urllib3.exceptions.HTTPError as e:\n            # catch-all for any other urllib3 response exceptions\n            raise TransportError(cause=e) from e\n\n\nclass RequestsHTTPAdapter(requests.adapters.HTTPAdapter):\n    def __init__(self, ssl_context=None, proxy_ssl_context=None, source_address=None, **kwargs):\n        self._pm_args = {}\n        if ssl_context:\n            self._pm_args['ssl_context'] = ssl_context\n        if source_address:\n            self._pm_args['source_address'] = (source_address, 0)\n        self._proxy_ssl_context = proxy_ssl_context or ssl_context\n        super().__init__(**kwargs)\n\n    def init_poolmanager(self, *args, **kwargs):","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/yt-dlp/yt-dlp/blob/81ecd58b1394793e6da9998cc19fdb45657f1685/yt_dlp/networking/_requests.py#L134-L170","documentation":"IncompleteRead (a TransportError) raised by the requests handler: urllib3 raised ProtocolError wrapping an http.client.IncompleteRead, meaning the server closed the connection before the full body arrived even though Content-Length promised more bytes. The message reports .partial = bytes actually read and .expected = bytes still owed; the original urllib3 exception is chained as __cause__.","triggerScenarios":"Server or an intermediary (proxy/CDN) truncates the response body; connection dropped mid-download; misranged requests where the server sends fewer bytes than declared; flaky mobile or VPN links during large downloads.","commonSituations":"Media downloads cut off by idle-connection kills; rate-limiting middleboxes closing streams early; HTTP/1.1 keep-alive races; servers with wrong Content-Length.","solutions":["Retry the request - yt-dlp retries fragments by default; raise --retries/--fragment-retries if it persists","Resume instead of restarting: rely on Range requests (yt-dlp does this for fragmented formats) so only the missing tail is refetched","Bypass the truncating middlebox: different network, disable VPN/proxy, or install the requests handler as an alternative path","If truncation is byte-stable and reproducible, the server is misreporting length - confirm with curl -C - and report the extractor/URL"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"import time\nfrom yt_dlp.networking.exceptions import IncompleteRead\n\nstart = 0\nfor attempt in range(5):\n    try:\n        return fetch(url, start_byte=start)\n    except IncompleteRead as e:\n        start = e.partial or start  # resume from what already arrived\n        time.sleep(1.5 ** attempt)\nraise TimeoutError('server keeps truncating the body')","preventionTips":["Enable generous --retries and --fragment-retries on unreliable links","Prefer resumable/ranged downloads so a truncated read is cheap to recover from","Log partial/expected - an identical truncation every time points at the server, not your network"],"tags":["networking","http","urllib3","truncated-response","download"],"backgroundTag":"incomplete-http-response","analyzedSha":"81ecd58b1394793e6da9998cc19fdb45657f1685","analyzedAt":"2026-08-22T12:21:25.439Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}