{"id":"c3f16c1b9ef6fd1b","repo":"pytest-dev/pytest","slug":"cannot-write-to-stdin-c3f16c","errorCode":null,"errorMessage":"Cannot write to stdin","messagePattern":"Cannot write to stdin","errorType":"exception","errorClass":"UnsupportedOperation","httpStatus":null,"severity":"error","filePath":"src/_pytest/capture.py","lineNumber":277,"sourceCode":"        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,\n    ) -> None:\n        pass\n\n    @property\n    def buffer(self) -> BinaryIO:\n        # The str/bytes doesn't actually matter in this type, so OK to fake.","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/capture.py#L259-L295","documentation":"Raised by DontReadFromInput.writelines() (capture.py:276-277), the batch write counterpart of write(). Like write(), it is intentionally disabled because the captured stdin pseudo-file is not writable (writable() returns False). The class replaces sys.stdin during captured test runs to prevent accidental I/O on a redirected stream.","triggerScenarios":"Calling sys.stdin.writelines(iterable), or handing sys.stdin to an API that uses writelines (e.g. some serializers/socket wrappers), while capture is on and stdin is the DontReadFromInput sentinel.","commonSituations":"Porting code from a real TTY where writelines on stdin was tolerated; test fixtures that pass sys.stdin as a 'file-like' sink; libraries that optimize bulk output via writelines regardless of the stream role.","solutions":["Run with -s / --capture=no to keep real stdin.","Route writelines to the correct stream (sys.stdout/stderr.writelines(lines)).","monkeypatch sys.stdin with an io.StringIO that supports writelines for the test.","Check `getattr(stream, 'writable', lambda: False)()` before calling writelines."],"exampleFix":"// before\nsys.stdin.writelines(lines)\n\n# after\nsys.stdout.writelines(lines)","handlingStrategy":"type-guard","validationCode":"def safe_writelines(stream, lines):\n    if getattr(stream, 'writable', lambda: False)():\n        stream.writelines(lines)","typeGuard":"def is_writable(stream) -> bool:\n    return bool(getattr(stream, 'writable', lambda: False)())","tryCatchPattern":"from io import UnsupportedOperation\ntry:\n    sys.stdin.writelines(lines)\nexcept UnsupportedOperation:\n    sys.stdout.writelines(lines)","preventionTips":["Target writelines at stdout/stderr or a buffer, never stdin.","For libs that call writelines on a passed stream, inject an io.StringIO in tests.","Use -s to disable the DontReadFromInput replacement."],"tags":["capture","stdin","writelines","unsupported-operation","pytest"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}