python/cpython · error · ValueError

raw stream already detached

Error message

raw stream already detached

What it means

BufferedRaw.detach (Lib/_pyio.py:823) raises ValueError when called on a buffered stream whose underlying raw object has already been detached (self.raw is None). detach() disassociates the raw stream and returns it for independent use; afterwards the buffered wrapper is unusable, and a second detach is rejected.

Source

Thrown at Lib/_pyio.py:823

    ### 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

    ### Inquiries ###

    def seekable(self):
        return self.raw.seekable()

    @property
    def raw(self):
        return self._raw

    @property
    def closed(self):
        return self.raw.closed

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Call detach() exactly once and keep the returned raw object as the single owner; stop using the buffered wrapper afterwards.
  2. If taking over a wrapper's buffer (e.g. sys.stdout), ensure no other code (print, logging, atexit, context-manager exit) uses or closes the wrapper afterwards.
  3. Check `buf.raw is not None` (guarded by try/except since raw is a property) or track detachment in your own state before detaching.

Example fix

# before
raw = wrapper.detach()
raw2 = wrapper.detach()  # ValueError: raw stream already detached

# after
raw = wrapper.detach()
del wrapper  # wrapper is spent; use raw directly from here on
Defensive patterns

Strategy: validation

Validate before calling

def detach_once(wrapper, state={'detached': False}):
    if state['detached']:
        raise ValueError('raw stream already detached earlier')
    state['detached'] = True
    return wrapper.detach()

Try / catch

try:
    raw = wrapper.detach()
except ValueError as e:
    if 'already detached' in str(e):
        raw = None  # already taken; handle ownership elsewhere
    else:
        raise

Prevention

When it happens

Trigger: Calling buf.detach() twice; calling read()/write()/flush() after detach() (these access self.raw, which is None, and most paths surface the detach error or AttributeError); detaching in cleanup code that runs again on retry.

Common situations: Taking over sys.stdin/sys.stdout buffers via sys.stdout.detach() or io.TextIOWrapper.detach() and then library code also touching or detaching the stream; mixing manual detach with `with` blocks that close the wrapper on exit.

Related errors


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