{"record":{"id":"9230334ee32cc98c","repo":"python/cpython","slug":"flush-on-closed-file","errorCode":null,"errorMessage":"flush on closed file","messagePattern":"flush on closed file","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pyio.py","lineNumber":810,"sourceCode":"        self._checkClosed()\n        self._checkWritable()\n\n        # Flush the stream.  We're mixing buffered I/O with lower-level I/O,\n        # and a flush may be necessary to synch both views of the current\n        # file state.\n        self.flush()\n\n        if pos is None:\n            pos = self.tell()\n        # XXX: Should seek() be used, instead of passing the position\n        # XXX  directly to truncate?\n        return self.raw.truncate(pos)\n\n    ### Flush and close ###\n\n    def flush(self):\n        if self.closed:\n            raise ValueError(\"flush on closed file\")\n        self.raw.flush()\n\n    def close(self):\n        if self.raw is not None and not self.closed:\n            try:\n                # may raise BlockingIOError or BrokenPipeError etc\n                self.flush()\n            finally:\n                self.raw.close()\n\n    def detach(self):\n        if self.raw is None:\n            raise ValueError(\"raw stream already detached\")\n        self.flush()\n        raw = self._raw\n        self._raw = None\n        return raw\n","sourceCodeStart":792,"sourceCodeEnd":828,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyio.py#L792-L828","documentation":"BufferedRaw.flush (Lib/_pyio.py:810) checks the closed flag before delegating to the raw stream's flush, raising ValueError when the buffered object has already been closed. This guard prevents writing buffered bytes to a raw descriptor that close() already released.","triggerScenarios":"Calling f.flush() after f.close(); flushing inside a `with` block's exit path after an exception already closed the stream; an explicit finally clause that flushes and then a later handler flushes again on a closed object; flushing a detached/closed buffer during interpreter shutdown.","commonSituations":"Cleanup code that calls both close() and flush() in inconsistent order; retry logic that flushes after an earlier attempt closed the file; __del__ or atexit handlers racing with explicit close.","solutions":["Only flush on an open stream: `if not f.closed: f.flush()` in cleanup paths.","Rely on close() itself — close() already calls flush() internally, so drop redundant explicit flushes before close.","Use `with` blocks so shutdown order is deterministic and flush happens exactly once."],"exampleFix":"# before\nf.close()\ntry:\n    f.flush()  # ValueError: flush on closed file\nfinally:\n    pass\n\n# after\nf.close()  # close() already flushes; or:\nif not f.closed:\n    f.flush()","handlingStrategy":"validation","validationCode":"def flush_if_open(f):\n    if not f.closed:\n        f.flush()","typeGuard":null,"tryCatchPattern":"try:\n    f.flush()\nexcept ValueError as e:\n    if 'closed file' not in str(e):\n        raise  # a real flush error (e.g. BrokenPipeError subclass paths) — re-raise","preventionTips":["close() already flushes; do not insert an extra flush before it.","In cleanup/finally code, always guard flush with `if not f.closed`.","Let `with` blocks own the flush-then-close sequence instead of hand-rolling it."],"tags":["io","flush","lifecycle","valueerror"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}