{"record":{"id":"6340e0b5aed71a4a","repo":"charmbracelet/bubbletea","slug":"error-entering-raw-mode-w","errorCode":null,"errorMessage":"error entering raw mode: %w","messagePattern":"error entering raw mode: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tty_unix.go","lineNumber":21,"sourceCode":"\npackage tea\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/charmbracelet/x/term\"\n)\n\nfunc (p *Program) initInput() (err error) {\n\t// Check if input is a terminal\n\tif f, ok := p.input.(term.File); ok && term.IsTerminal(f.Fd()) {\n\t\tp.ttyInput = f\n\t\tp.previousTtyInputState, err = term.MakeRaw(p.ttyInput.Fd())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error entering raw mode: %w\", err)\n\t\t}\n\n\t\t// OPTIM: We can use hard tabs and backspaces to optimize cursor\n\t\t// movements. This is based on termios settings support and whether\n\t\t// they exist and enabled.\n\t\tp.checkOptimizedMovements(p.previousTtyInputState)\n\t}\n\n\tif f, ok := p.output.(term.File); ok && term.IsTerminal(f.Fd()) {\n\t\tp.ttyOutput = f\n\t}\n\n\treturn nil\n}\n\nconst suspendSupported = true\n\n// Send SIGTSTP to the entire process group.","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/charmbracelet/bubbletea/blob/351d2159f8d8a85613aa2a6e98c8c63df3c98623/tty_unix.go#L3-L39","documentation":"Bubble Tea failed to put the terminal into raw mode on a Unix-like system while initializing input. initInput() calls term.MakeRaw() on the stdin file descriptor (an ioctl TCGETS/TCSETS on the fd), and the kernel rejected it — typically ENOTTY, EBADF, or EACCES. The wrapped error is returned from Program.Run() via initTerminal(), so the program never starts.","triggerScenarios":"Running a Program whose p.input implements term.File and passes term.IsTerminal(), but whose fd cannot actually be switched to raw mode: a closed stdin fd, a pty that lost its controlling side, a /dev/tty that is not accessible, or a pseudo-terminal granted by a sandbox/container without full termios permissions.","commonSituations":"Piping or redirecting stdin in shells or CI (input is a pipe but a wrapping pty still reports a terminal), running under `go test` with no real tty, detached processes or daemons that kept a stale terminal fd, containers/seccomp profiles blocking TCSETS ioctls, and SSH sessions that dropped while the program was starting.","solutions":["Check the wrapped error's underlying errno: run with the full chain printed (`%+v` or errors.Unwrap) — ENOTTY means the fd is not a real terminal, EBADF means it is closed.","Ensure stdin is a real tty before starting: if term.IsTerminal(os.Stdin.Fd()) is false, run with tea.WithInput(nil) or a non-tty input so Bubble Tea skips raw mode.","If you need a tty in a non-interactive context (tests, CI), allocate a pty (e.g. creack/pty) and pass it via tea.WithInput(ptmx) / tea.WithOutput(ptmx).","For headless rendering, start the program with tea.WithoutRenderer() — initTerminal() returns nil early and raw mode is never attempted.","Reopen /dev/tty explicitly with tea.OpenTTY() and feed the returned files to WithInput/WithOutput when the original stdin fd is stale or closed."],"exampleFix":"// before\np := tea.NewProgram(model{})\nif _, err := p.Run(); err != nil {\n    log.Fatalf(\"run: %v\", err) // error entering raw mode: inappropriate ioctl for device\n}\n\n// after\nin, out, err := tea.OpenTTY() // fresh, real terminal handles\nif err != nil {\n    log.Fatalf(\"open tty: %v\", err)\n}\ndefer in.Close()\ndefer out.Close()\np := tea.NewProgram(model{}, tea.WithInput(in), tea.WithOutput(out))","handlingStrategy":"try-catch","validationCode":"if f, ok := stdin.(term.File); ok && !term.IsTerminal(f.Fd()) {\n    // not a real terminal: raw mode will fail\n    stdin = nil // or a pipe\n}\np := tea.NewProgram(model, tea.WithInput(stdin))","typeGuard":"func isRealTTY(f term.File) bool {\n    return term.IsTerminal(f.Fd())\n}","tryCatchPattern":"if _, err := p.Run(); err != nil {\n    var rawErr error\n    if strings.Contains(err.Error(), \"error entering raw mode\") {\n        rawErr = errors.Unwrap(err)\n    }\n    switch {\n    case rawErr == nil:\n        log.Fatalf(\"program error: %v\", err)\n    case errors.Is(rawErr, unix.ENOTTY):\n        log.Fatal(\"stdin is not a terminal; run interactively or use tea.WithInput(nil)\")\n    case errors.Is(rawErr, unix.EBADF):\n        log.Fatal(\"stdin fd is closed; reopen with tea.OpenTTY()\")\n    default:\n        log.Fatalf(\"terminal init failed: %v\", err)\n    }\n}","preventionTips":["Never pipe stdin into a full Bubble Tea program; branch on term.IsTerminal(os.Stdin.Fd()) and use tea.WithInput(nil) for non-interactive runs.","In tests and CI, allocate a real pty (creack/pty) and pass it via tea.WithInput/WithOutput instead of relying on the runner's stdin.","Use tea.OpenTTY() when the process may have been started with a stale or redirected stdin.","For programs that must run headless, start with tea.WithoutRenderer() — it skips raw-mode setup entirely."],"tags":["terminal","tty","raw-mode","unix","bubbletea","initialization"],"backgroundTag":null,"analyzedSha":"351d2159f8d8a85613aa2a6e98c8c63df3c98623","analyzedAt":"2026-08-15T10:48:22.366Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}