{"record":{"id":"48c116aacbb6d2ff","repo":"python/cpython","slug":"write-to-closed-file","errorCode":null,"errorMessage":"write to closed file","messagePattern":"write to closed file","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pyio.py","lineNumber":960,"sourceCode":"                size = len(self._buffer)\n            if len(self._buffer) <= self._pos:\n                return b\"\"\n            newpos = min(len(self._buffer), self._pos + size)\n            b = self._buffer[self._pos : newpos]\n            self._pos = newpos\n            return b.take_bytes()\n\n    def read1(self, size=-1):\n        \"\"\"This is the same as read.\n        \"\"\"\n        return self.read(size)\n\n    def write(self, b):\n        if isinstance(b, str):\n            raise TypeError(\"can't write str to binary stream\")\n        with memoryview(b) as view:\n            if self.closed:\n                raise ValueError(\"write to closed file\")\n\n            n = view.nbytes  # Size of any bytes-like object\n            if n == 0:\n                return 0\n\n            with self._lock:\n                pos = self._pos\n                if pos > len(self._buffer):\n                    # Pad buffer to pos with null bytes.\n                    self._buffer.resize(pos)\n                self._buffer[pos:pos + n] = view\n                self._pos += n\n            return n\n\n    def seek(self, pos, whence=0):\n        if self.closed:\n            raise ValueError(\"seek on closed file\")\n        try:","sourceCodeStart":942,"sourceCodeEnd":978,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyio.py#L942-L978","documentation":"BytesIO.write (Lib/_pyio.py:960) checks the closed flag inside the memoryview context before mutating the buffer and raises ValueError('write to closed file'). After close() the internal bytearray has been swapped for an empty one, so a late write would either fail confusingly or appear to lose data — the check makes the state explicit.","triggerScenarios":"buf.write(b'...') after buf.close(); writing inside a loop where an earlier iteration's error handler closed the stream; a `with io.BytesIO()` block exited before a deferred/batched write executes.","commonSituations":"Buffered writers that accumulate output and flush/close on error, with later code still writing; async tasks writing to a shared BytesIO closed by cancellation; generator pipelines where close propagates downstream early.","solutions":["Ensure close() runs only after the last write; reorder cleanup to the very end.","Guard writes on shared streams: `if not buf.closed: buf.write(chunk)`.","On cancellation/error paths, drain or finalize pending writes before closing the buffer."],"exampleFix":"# before\nbuf = io.BytesIO()\ntry:\n    for chunk in source():\n        buf.write(chunk)\nexcept ValueError:\n    buf.close()\n    buf.write(b'partial')  # ValueError: write to closed file\n\n# after\nbuf = io.BytesIO()\ntry:\n    for chunk in source():\n        buf.write(chunk)\nexcept ValueError:\n    pass  # keep buf open\nfinally:\n    result = buf.getvalue()\n    buf.close()  # close once, at the end","handlingStrategy":"validation","validationCode":"def write_if_open(buf: io.BytesIO, chunk: bytes) -> int:\n    if buf.closed:\n        raise ValueError('BytesIO closed; writes must happen before close')\n    return buf.write(chunk)","typeGuard":"def is_open_bytesio(v) -> bool:\n    return isinstance(v, io.BytesIO) and not v.closed","tryCatchPattern":"try:\n    buf.write(chunk)\nexcept ValueError as e:\n    if 'closed file' in str(e):\n        raise RuntimeError('writer ran after buffer close; reorder cleanup') from e\n    raise","preventionTips":["Perform all writes before close(); treat close as the final operation.","In async/cancel paths, finalize pending writes before closing the buffer.","Omit explicit close() for BytesIO when ownership is murky — GC handles it."],"tags":["io","bytesio","write","lifecycle","valueerror"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}