{"id":"8c3f6a35f48fa754","repo":"urllib3/urllib3","slug":"unable-to-determine-whether-fp-is-closed","errorCode":null,"errorMessage":"Unable to determine whether fp is closed.","messagePattern":"Unable to determine whether fp is closed\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/urllib3/util/response.py","lineNumber":37,"sourceCode":"        # GH Issue #928\n        return obj.isclosed()  # type: ignore[no-any-return, attr-defined]\n    except AttributeError:\n        pass\n\n    try:\n        # Check via the official file-like-object way.\n        return obj.closed  # type: ignore[no-any-return, attr-defined]\n    except AttributeError:\n        pass\n\n    try:\n        # Check if the object is a container for another file-like object that\n        # gets released on exhaustion (e.g. HTTPResponse).\n        return obj.fp is None  # type: ignore[attr-defined]\n    except AttributeError:\n        pass\n\n    raise ValueError(\"Unable to determine whether fp is closed.\")\n\n\ndef assert_header_parsing(headers: httplib.HTTPMessage) -> None:\n    \"\"\"\n    Asserts whether all headers have been successfully parsed.\n    Extracts encountered errors from the result of parsing headers.\n\n    Only works on Python 3.\n\n    :param http.client.HTTPMessage headers: Headers to verify.\n\n    :raises urllib3.exceptions.HeaderParsingError:\n        If parsing errors are found.\n    \"\"\"\n\n    # This will fail silently if we pass in the wrong kind of parameter.\n    # To make debugging easier add an explicit check.\n    if not isinstance(headers, httplib.HTTPMessage):","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/urllib3/urllib3/blob/c8d039c1b743f0bf5ee136972c68350fd91d41f1/src/urllib3/util/response.py#L19-L55","documentation":"Raised as ValueError from is_fp_closed() when the supplied file-like object has none of: isclosed() method, closed attribute, or fp attribute. urllib3 uses these three duck-typed signals (in that order) to decide if a response stream is exhausted; if none exists it cannot make a determination and refuses to guess.","triggerScenarios":"Passing an arbitrary object to is_fp_closed() that doesn't resemble a file-like/HTTPResponse; using a custom body wrapper that omits all three signals; contrib backends whose body object lacks the expected interface.","commonSituations":"Test doubles/mocks that implement read() but nothing else; third-party transports that wrap responses in plain objects; legacy Python 2 shims that lost the closed attribute.","solutions":["Ensure custom file-like bodies inherit from io.IOBase (which provides .closed) or expose at least one of isclosed/closed/fp.","Avoid calling urllib3.util.response.is_fp_closed() on objects that aren't response-like; use resp.closed on HTTPResponse directly.","For mocks, set the closed attribute explicitly (mock.closed = True/False)."],"exampleFix":"// before\nclass MyBody:\n    def read(self, n=-1): return b''\nis_fp_closed(MyBody())  # raises ValueError\n\n// after\nimport io\nclass MyBody(io.IOBase):\n    def read(self, n=-1): return b''\n# .closed is now provided by io.IOBase","handlingStrategy":"type-guard","validationCode":"def fp_closed(fp):\n    for attr in ('isclosed', 'closed'):\n        if hasattr(fp, attr):\n            return getattr(fp, attr)\n    if hasattr(fp, 'fp'):\n        return fp.fp is None\n    raise ValueError('object is not a recognizable file-like response')","typeGuard":"def looks_like_response_fp(obj) -> bool:\n    return any(hasattr(obj, a) for a in ('isclosed', 'closed', 'fp'))","tryCatchPattern":"try:\n    closed = is_fp_closed(obj)\nexcept ValueError:\n    closed = True  # unknown shape; assume closed to stop iterating","preventionTips":["Inherit custom file-like bodies from io.IOBase","Don't pass arbitrary objects to is_fp_closed"],"tags":["http","file-like","validation","duck-typing"],"analyzedSha":"c8d039c1b743f0bf5ee136972c68350fd91d41f1","analyzedAt":"2026-08-04T20:12:33.219Z","schemaVersion":2}