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
- Run pytest with -s (or --capture=no) to disable stdin replacement entirely
- Inside the test, stop capture explicitly via capture_fixture.stop() (capsys.stop()/capfd.stop()) before seeking
- Replace sys.stdin with an io.StringIO before the seek; do not rely on the captured pseudo-file
- 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
- Always probe seekable() before calling seek() on a stream you do not own
- Run pytest with -s for tests that genuinely need real stdin semantics
- Inject io.StringIO into sys.stdin in fixtures rather than relying on pytest's pseudo-file
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
- cannot truncate stdin
- cannot write to stdin
- Cannot write to stdin
- redirected stdin is pseudofile, has no tell()
- pytest: reading from stdin while output is captured! …
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 FalseView on GitHub (pinned to 0d6fbdeffa)