python/cpython · error · RuntimeError

termios failure ({e.args[1]})

Error message

termios failure ({e.args[1]})

What it means

RuntimeError raised in UnixConsole.__init__ (Lib/_pyrepl/unix_console.py). During console setup the code calls tcgetattr on the input fd and pipes it through __input_fd_set; if that underlying termios call fails (termios.error), the code re-raises as RuntimeError with the OS error string from e.args[1] (e.g. 'Inappropriate ioctl for device').

Source

Thrown at Lib/_pyrepl/unix_console.py:225

        - f_out (int or file-like object): Output file descriptor or object.
        - term (str): Terminal name.
        - encoding (str): Encoding to use for I/O operations.
        """
        super().__init__(f_in, f_out, term, encoding)

        self.pollob = poll()
        self.pollob.register(self.input_fd, select.POLLIN)
        self.terminfo = terminfo.TermInfo(term or None)
        self.term = term
        self.is_apple_terminal = (
            platform.system() == "Darwin"
            and os.getenv("TERM_PROGRAM") == "Apple_Terminal"
        )

        try:
            self.__input_fd_set(tcgetattr(self.input_fd), ignore=frozenset())
        except _error as e:
            raise RuntimeError(f"termios failure ({e.args[1]})")

        @overload
        def _my_getstr(
            cap: str, optional: Literal[False] = False
        ) -> bytes: ...

        @overload
        def _my_getstr(cap: str, optional: bool) -> bytes | None: ...

        def _my_getstr(cap: str, optional: bool = False) -> bytes | None:
            r = self.terminfo.get(cap)
            if not optional and r is None:
                raise InvalidTerminal(
                    f"terminal doesn't have the required {cap} capability"
                )
            return r

        self._bel = _my_getstr("bel")

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Ensure the process actually owns a real terminal before constructing UnixConsole: run docker/exec with -t, allocate a PTY (pty.openpty/os.openpty) and dup it onto fd 0.
  2. Check os.isatty(sys.stdin.fileno()) immediately before construction, not only at import time.
  3. If embedding, catch RuntimeError here and fall back to plain input() or readline-based interaction.

Example fix

# before
console = UnixConsole()  # RuntimeError: termios failure (...) when stdin lacks termios

# after
import os, sys
if not os.isatty(sys.stdin.fileno()):
    raise SystemExit('pyrepl needs a tty on stdin; run with a pty')
console = UnixConsole()
Defensive patterns

Strategy: try-catch

Validate before calling

import os, sys

def console_ready():
    try:
        return os.isatty(sys.stdin.fileno())
    except (OSError, ValueError):
        return False

Try / catch

try:
    from _pyrepl.unix_console import UnixConsole
    console = UnixConsole()
except (RuntimeError, OSError) as e:
    raise SystemExit(f'cannot start interactive console: {e}') from e

Prevention

When it happens

Trigger: Constructing UnixConsole (or starting the pyrepl REPL) when the input fd is not a terminal or the termios state is unavailable: stdin redirected to a file/pipe despite other checks passing, fd already closed, or a PTY that does not support termios ioctls. tcgetattr raising termios.error is the trigger.

Common situations: Embedding pyrepl in tools where stdin was swapped after import-time isatty checks; spawning the REPL under process supervisors that give a half-open PTY; race where the tty is closed by another thread between the isatty check and tcgetattr; exotic terminals (some CI docker setups without -t).

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/005ae681fbcd332a. Report an issue: GitHub.