{"record":{"id":"f716e0da6f49856c","repo":"python/cpython","slug":"i-o-operation-on-closed-file","errorCode":null,"errorMessage":"I/O operation on closed file.","messagePattern":"I/O operation on closed file\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pyio.py","lineNumber":477,"sourceCode":"        \"\"\"Internal: raise UnsupportedOperation if file is not writable\n        \"\"\"\n        if not self.writable():\n            raise UnsupportedOperation(\"File or stream is not writable.\"\n                                       if msg is None else msg)\n\n    @property\n    def closed(self):\n        \"\"\"closed: bool.  True iff the file has been closed.\n\n        For backwards compatibility, this is a property, not a predicate.\n        \"\"\"\n        return self.__closed\n\n    def _checkClosed(self, msg=None):\n        \"\"\"Internal: raise a ValueError if file is closed\n        \"\"\"\n        if self.closed:\n            raise ValueError(\"I/O operation on closed file.\"\n                             if msg is None else msg)\n\n    ### Context manager ###\n\n    def __enter__(self):  # That's a forward reference\n        \"\"\"Context management protocol.  Returns self (an instance of IOBase).\"\"\"\n        self._checkClosed()\n        return self\n\n    def __exit__(self, *args):\n        \"\"\"Context management protocol.  Calls close()\"\"\"\n        self.close()\n\n    ### Lower-level APIs ###\n\n    # XXX Should these be present even if unimplemented?\n\n    def fileno(self):","sourceCodeStart":459,"sourceCodeEnd":495,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyio.py#L459-L495","documentation":"Raised by IOBase._checkClosed (Lib/_pyio.py:477) when any I/O operation is attempted on a file object whose close() has already run. The closed property is set to True by close(), and nearly every public method (read, write, seek, flush, __enter__) funnels through this guard. It is a ValueError, signaling a lifecycle bug in the caller's code rather than an OS-level failure.","triggerScenarios":"Calling f.read()/f.write()/f.seek()/f.flush()/f.__enter__() after f.close(); using a file object after its `with` block has exited (the context manager's __exit__ calls close()); accessing a file that another function closed; double-processing a file in a loop where the first iteration closed it.","commonSituations":"Returning a file object from a `with open(...)` block and using it later; helper functions that take ownership of and close a stream the caller still uses; background threads or generators that close shared files; refactoring that moved a close() above later operations.","solutions":["Move all file operations inside the `with open(...) as f:` block so close happens only after the last use.","If the file must outlive the current scope, open it without `with` and explicitly close it in a finally after the final consumer is done.","Guard calls with `if not f.closed:` before operating on a shared or long-lived file object.","Audit for double-ownership: find every close(), detach(), or `with` that touches the object and ensure exactly one owner closes it."],"exampleFix":"// before\ndef load(path):\n    with open(path, 'rb') as f:\n        return f\nf = load('data.bin')\nf.read()  # ValueError: I/O operation on closed file.\n\n# after\ndef load(path):\n    with open(path, 'rb') as f:\n        return f.read()\ndata = load('data.bin')","handlingStrategy":"validation","validationCode":"def safe_read(f, n=-1):\n    if f.closed:\n        raise ValueError('file already closed; reopen before use')\n    return f.read(n)","typeGuard":"def is_open_binary(f) -> bool:\n    return isinstance(f, io.IOBase) and not f.closed","tryCatchPattern":"try:\n    data = f.read()\nexcept ValueError as e:\n    if 'closed file' in str(e):\n        f = open(path, 'rb')  # reopen and retry once\n        data = f.read()\n    else:\n        raise","preventionTips":["Use `with open(...) as f:` for every file whose lifetime fits one scope.","Never return file objects from functions that opened them inside a with-block — return the data instead.","Establish a single owner responsible for close(); document it at the API boundary.","Check f.closed before operating on streams received from other modules."],"tags":["io","file","lifecycle","valueerror"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}