pytest-dev/pytest · error · UnsupportedOperation

cannot truncate stdin

Error message

cannot truncate stdin

What it means

Raised by DontReadFromInput.truncate() (src/_pytest/capture.py:270). truncate() is rejected because the pseudo-file backing redirected stdin is read-only and not size-addressable; pytest raises UnsupportedOperation rather than silently no-op. writable() returns False to advertise.

Solutions

  1. Guard the call: only truncate() on objects whose writable() returns True
  2. Disable capture with -s so sys.stdin is the real stream
  3. try/except OSError around the truncate call
  4. Stop the capture fixture (capsys.stop()) before calling truncate

Example fix

// before
sys.stdin.truncate(0)
// after
if sys.stdin.writable():
    sys.stdin.truncate(0)
Defensive patterns

Strategy: try-catch

Validate before calling

import sys
if not sys.stdin.writable():
    pass

Type guard

def can_truncate(stream) -> bool:
    try:
        return stream.writable()
    except Exception:
        return False

Try / catch

try:
    sys.stdin.truncate(size)
except OSError:
    pass

Prevention

When it happens

Trigger: Invoking sys.stdin.truncate([size]) while capture is on. capture.py:270-271 raises unconditionally with no probe method (truncate has no standard boolean predicate), so the call must be wrapped.

Common situations: Edge case from stream-rewriting helpers, mock libraries that walk file objects, or io.MultiFile-style code that calls truncate() defensively on every handle including stdin.

Related errors


AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11). Data as JSON: /api/errors/a695831d067973a2. Report an issue: GitHub.

Appendix: 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 0d6fbdeffa)