{"record":{"id":"1dd18f7ab7af60b5","repo":"python/cpython","slug":"enotty","errorCode":"ENOTTY","errorMessage":"tty required","messagePattern":"tty required","errorType":"console","errorClass":"OSError","httpStatus":null,"severity":"warning","filePath":"Lib/_pyrepl/main.py","lineNumber":13,"sourceCode":"import errno\nimport os\nimport sys\nimport types\n\n\nCAN_USE_PYREPL: bool\nFAIL_REASON: str\ntry:\n    if sys.platform == \"win32\" and sys.getwindowsversion().build < 10586:\n        raise RuntimeError(\"Windows 10 TH2 or later required\")\n    if not os.isatty(sys.stdin.fileno()):\n        raise OSError(errno.ENOTTY, \"tty required\", \"stdin\")\n    from .simple_interact import check\n    if err := check():\n        raise RuntimeError(err)\nexcept Exception as e:\n    CAN_USE_PYREPL = False\n    FAIL_REASON = f\"warning: can't use pyrepl: {e}\"\nelse:\n    CAN_USE_PYREPL = True\n    FAIL_REASON = \"\"\n\n\ndef interactive_console(mainmodule=None, quiet=False, pythonstartup=False):\n    if not CAN_USE_PYREPL:\n        if not os.getenv('PYTHON_BASIC_REPL') and FAIL_REASON:\n            from .trace import trace\n            trace(FAIL_REASON)\n            print(FAIL_REASON, file=sys.stderr)\n        return sys._baserepl()","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyrepl/main.py#L1-L31","documentation":"OSError with errno ENOTTY raised at import time of _pyrepl.main when sys.stdin is not a TTY (piped input, redirected file, or non-terminal stream). Like the Windows check, it is raised inside a try/except that swallows it: CAN_USE_PYREPL becomes False and FAIL_REASON records the message, so Python silently falls back to the plain REPL/read-from-stdin behavior.","triggerScenarios":"Importing _pyrepl.main (implicitly via the interactive interpreter) while stdin is a pipe or file: python < script.py in interactive mode, python -i fed by a pipe, REPL launched inside process substitution, or stdin closed. os.isatty(sys.stdin.fileno()) returning False is the exact trigger.","commonSituations":"Running the REPL under piping tools (cat file | python -i), debuggers/embedders that replace stdin, CI harnesses that open REPL sessions with redirected stdin, and terminal multiplexer misconfigurations. Only symptom is 'warning: can't use pyrepl: [Errno 25] tty required: stdin' at startup.","solutions":["This is expected behavior, not a bug — feed a real terminal. Run python in a PTY (pty.openpty, pexpect, or 'script -qc \"python\" /dev/null') when embedding.","For scripted input, don't use the interactive REPL at all: pass the script path or use python -c / stdin as a file (python file.py), which never imports _pyrepl.main.","Set PYTHON_BASIC_REPL=1 to skip the pyrepl check and message if the warning is noise."],"exampleFix":"# before\n# cat cmds.txt | python -i   -> warning: can't use pyrepl: tty required\n\n# after\n# python -i cmds.txt        -> runs script then interactive, no pyrepl warning\n# or embed with a pty:\nimport pexpect\npexpect.spawn('python')  # gives the child a real tty","handlingStrategy":"validation","validationCode":"import os, sys\n\ndef repl_possible():\n    try:\n        return os.isatty(sys.stdin.fileno())\n    except (OSError, ValueError):\n        return False","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Give the REPL a real tty: allocate a PTY (pexpect, pty.openpty) when embedding.","For scripted input use python -i script.py or plain scripts, not piped stdin.","Set PYTHON_BASIC_REPL=1 to skip pyrepl selection deterministically."],"tags":["python","repl","pyrepl","tty","stdin","startup"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}