{"id":"a695831d067973a2","repo":"pytest-dev/pytest","slug":"cannot-truncate-stdin","errorCode":null,"errorMessage":"cannot truncate stdin","messagePattern":"cannot truncate stdin","errorType":"exception","errorClass":"UnsupportedOperation","httpStatus":null,"severity":"warning","filePath":"src/_pytest/capture.py","lineNumber":271,"sourceCode":"        return False\n\n    def close(self) -> None:\n        pass\n\n    def readable(self) -> bool:\n        return False\n\n    def seek(self, offset: int, whence: int = 0) -> int:\n        raise UnsupportedOperation(\"redirected stdin is pseudofile, has no seek(int)\")\n\n    def seekable(self) -> bool:\n        return False\n\n    def tell(self) -> int:\n        raise UnsupportedOperation(\"redirected stdin is pseudofile, has no tell()\")\n\n    def truncate(self, size: int | None = None) -> int:\n        raise UnsupportedOperation(\"cannot truncate stdin\")\n\n    def write(self, data: str) -> int:\n        raise UnsupportedOperation(\"cannot write to stdin\")\n\n    def writelines(self, lines: Iterable[str]) -> None:\n        raise UnsupportedOperation(\"Cannot write to stdin\")\n\n    def writable(self) -> bool:\n        return False\n\n    def __enter__(self) -> Self:\n        return self\n\n    def __exit__(\n        self,\n        type: type[BaseException] | None,\n        value: BaseException | None,\n        traceback: TracebackType | None,","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/capture.py#L253-L289","documentation":"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).","triggerScenarios":"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.","commonSituations":"A utility that resets streams via truncate; code that confuses stdin with a writable output stream; defensive cleanup routines iterating over standard streams.","solutions":["Run pytest with -s.","Refactor to only truncate writable streams (check writable() first).","Do not call truncate on stdin at all — stdin is conceptually read-only."],"exampleFix":"// before\n# code: for s in (sys.stdin, sys.stdout, sys.stderr): s.truncate(0)\n// after\n# code: for s in (sys.stdout, sys.stderr):\n#           if s.writable() and s.seekable(): s.seek(0); s.truncate(0)","handlingStrategy":"try-catch","validationCode":"def safe_truncate(stream, size=None):\n    if not getattr(stream, 'writable', lambda: False)():\n        return  # stdin is not writable; nothing to do\n    return stream.truncate(size)","typeGuard":"def is_writable(stream) -> bool:\n    return bool(getattr(stream, 'writable', lambda: False)())","tryCatchPattern":"from io import UnsupportedOperation\ntry:\n    stream.truncate(0)\nexcept (OSError, UnsupportedOperation, ValueError):\n    pass","preventionTips":["Never call truncate on stdin; it is conceptually read-only.","Check writable() before truncate/seek on generic streams."],"tags":["pytest","capture","stdin","io"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}