pytest-dev/pytest · error · UnsupportedOperation

redirected stdin is pseudofile, has no seek(int)

Error message

redirected stdin is pseudofile, has no seek(int)

What it means

Raised by DontReadFromInput.seek() (src/_pytest/capture.py:261). When pytest captures output (default behavior), it replaces sys.stdin with a DontReadFromInput pseudo-file that blocks all read/seek/tell/write operations. seek() raises UnsupportedOperation (an OSError/ValueError subclass) because redirected stdin is not a real file and has no position cursor. The class advertises this via seekable() returning False.

Solutions

  1. Run pytest with -s (or --capture=no) to disable stdin replacement entirely
  2. Inside the test, stop capture explicitly via capture_fixture.stop() (capsys.stop()/capfd.stop()) before seeking
  3. Replace sys.stdin with an io.StringIO before the seek; do not rely on the captured pseudo-file
  4. Gate the seek with `if sys.stdin.seekable():` so DontReadFromInput at capture.py:264 short-circuits

Example fix

// before
sys.stdin.seek(0)
// after
if sys.stdin.seekable():
    sys.stdin.seek(0)
Defensive patterns

Strategy: try-catch

Validate before calling

import sys
if not sys.stdin.seekable():
    # pytest capture is active; skip seek
    pass

Type guard

def can_seek(stream) -> bool:
    try:
        return stream.seekable()
    except Exception:
        return False

Try / catch

from io import UnsupportedOperation
try:
    sys.stdin.seek(0)
except (UnsupportedOperation, OSError):
    # pytest DontReadFromInput - capture is on
    pass

Prevention

When it happens

Trigger: Calling sys.stdin.seek(offset[, whence]) inside a test while output capture is on (the default). The seek() call at capture.py:261 unconditionally raises; seekable() at capture.py:264 returns False so callers that probe first are safe.

Common situations: Test helpers or libraries under test (CLIs using prompt_toolkit, doctest harnesses, replay frameworks) call sys.stdin.seek(0) to rewind piped input. Also triggered when a test stubs sys.stdin with a real file then pytest's capture re-wraps it.

Related errors


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

Appendix: source

Thrown at src/_pytest/capture.py:262

        return self

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

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

    def isatty(self) -> bool:
        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

View on GitHub (pinned to 0d6fbdeffa)