python/cpython · warning · OSError
ENOTTY
ENOTTY
Error message
tty required
What it means
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.
Source
Thrown at Lib/_pyrepl/main.py:13
import errno
import os
import sys
import types
CAN_USE_PYREPL: bool
FAIL_REASON: str
try:
if sys.platform == "win32" and sys.getwindowsversion().build < 10586:
raise RuntimeError("Windows 10 TH2 or later required")
if not os.isatty(sys.stdin.fileno()):
raise OSError(errno.ENOTTY, "tty required", "stdin")
from .simple_interact import check
if err := check():
raise RuntimeError(err)
except Exception as e:
CAN_USE_PYREPL = False
FAIL_REASON = f"warning: can't use pyrepl: {e}"
else:
CAN_USE_PYREPL = True
FAIL_REASON = ""
def interactive_console(mainmodule=None, quiet=False, pythonstartup=False):
if not CAN_USE_PYREPL:
if not os.getenv('PYTHON_BASIC_REPL') and FAIL_REASON:
from .trace import trace
trace(FAIL_REASON)
print(FAIL_REASON, file=sys.stderr)
return sys._baserepl()View on GitHub (pinned to bc6749cc3b)
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.
Example fix
# before
# cat cmds.txt | python -i -> warning: can't use pyrepl: tty required
# after
# python -i cmds.txt -> runs script then interactive, no pyrepl warning
# or embed with a pty:
import pexpect
pexpect.spawn('python') # gives the child a real tty Defensive patterns
Strategy: validation
Validate before calling
import os, sys
def repl_possible():
try:
return os.isatty(sys.stdin.fileno())
except (OSError, ValueError):
return False Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Windows 10 TH2 or later required
- \C must be followed by `-' (char %d of %s)
- doubled \C- (char %d of %s)
- \M must be followed by `-' (char %d of %s)
- doubled \M- (char %d of %s)
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/1dd18f7ab7af60b5.
Report an issue: GitHub.