python/cpython · error · ValueError

flush on closed file

Error message

flush on closed file

What it means

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.

Source

Thrown at Lib/_pyio.py:810

        self._checkClosed()
        self._checkWritable()

        # Flush the stream.  We're mixing buffered I/O with lower-level I/O,
        # and a flush may be necessary to synch both views of the current
        # file state.
        self.flush()

        if pos is None:
            pos = self.tell()
        # XXX: Should seek() be used, instead of passing the position
        # XXX  directly to truncate?
        return self.raw.truncate(pos)

    ### Flush and close ###

    def flush(self):
        if self.closed:
            raise ValueError("flush on closed file")
        self.raw.flush()

    def close(self):
        if self.raw is not None and not self.closed:
            try:
                # may raise BlockingIOError or BrokenPipeError etc
                self.flush()
            finally:
                self.raw.close()

    def detach(self):
        if self.raw is None:
            raise ValueError("raw stream already detached")
        self.flush()
        raw = self._raw
        self._raw = None
        return raw

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Only flush on an open stream: `if not f.closed: f.flush()` in cleanup paths.
  2. Rely on close() itself — close() already calls flush() internally, so drop redundant explicit flushes before close.
  3. Use `with` blocks so shutdown order is deterministic and flush happens exactly once.

Example fix

# before
f.close()
try:
    f.flush()  # ValueError: flush on closed file
finally:
    pass

# after
f.close()  # close() already flushes; or:
if not f.closed:
    f.flush()
Defensive patterns

Strategy: validation

Validate before calling

def flush_if_open(f):
    if not f.closed:
        f.flush()

Try / catch

try:
    f.flush()
except ValueError as e:
    if 'closed file' not in str(e):
        raise  # a real flush error (e.g. BrokenPipeError subclass paths) — re-raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/9230334ee32cc98c. Report an issue: GitHub.