pytest-dev/pytest · warning · UnsupportedOperation

cannot truncate stdin

Error message

cannot truncate stdin

What it means

DontReadFromInput.truncate() raises UnsupportedOperation because the captured stdin pseudo-file is a read-only in-memory stream; truncating it is meaningless (and stdin is not writable to begin with).

Source

Thrown at src/_pytest/capture.py:271

        return False

    def close(self) -> None:
        pass

    def readable(self) -> bool:
        return False

    def seek(self, offset: int, whence: int = 0) -> int:
        raise UnsupportedOperation("redirected stdin is pseudofile, has no seek(int)")

    def seekable(self) -> bool:
        return False

    def tell(self) -> int:
        raise UnsupportedOperation("redirected stdin is pseudofile, has no tell()")

    def truncate(self, size: int | None = None) -> int:
        raise UnsupportedOperation("cannot truncate stdin")

    def write(self, data: str) -> int:
        raise UnsupportedOperation("cannot write to stdin")

    def writelines(self, lines: Iterable[str]) -> None:
        raise UnsupportedOperation("Cannot write to stdin")

    def writable(self) -> bool:
        return False

    def __enter__(self) -> Self:
        return self

    def __exit__(
        self,
        type: type[BaseException] | None,
        value: BaseException | None,
        traceback: TracebackType | None,

View on GitHub (pinned to 98b357f69e)

Solutions

  1. Run pytest with -s.
  2. Refactor to only truncate writable streams (check writable() first).
  3. Do not call truncate on stdin at all — stdin is conceptually read-only.

Example fix

// before
# code: for s in (sys.stdin, sys.stdout, sys.stderr): s.truncate(0)
// after
# code: for s in (sys.stdout, sys.stderr):
#           if s.writable() and s.seekable(): s.seek(0); s.truncate(0)
Defensive patterns

Strategy: try-catch

Validate before calling

def safe_truncate(stream, size=None):
    if not getattr(stream, 'writable', lambda: False)():
        return  # stdin is not writable; nothing to do
    return stream.truncate(size)

Type guard

def is_writable(stream) -> bool:
    return bool(getattr(stream, 'writable', lambda: False)())

Try / catch

from io import UnsupportedOperation
try:
    stream.truncate(0)
except (OSError, UnsupportedOperation, ValueError):
    pass

Prevention

When it happens

Trigger: In a test under default capture, code calls sys.stdin.truncate(...) — usually a generic stream-management routine that calls truncate on every file-like object.

Common situations: A utility that resets streams via truncate; code that confuses stdin with a writable output stream; defensive cleanup routines iterating over standard streams.

Related errors


AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04). Data as JSON: /data/errors/a695831d067973a2.json. Report an issue: GitHub.