{"record":{"id":"002b5c38bc89d30f","repo":"Hmbown/CodeWhale","slug":"failed-to-enable-raw-mode-e","errorCode":null,"errorMessage":"Failed to enable raw mode: {e}","messagePattern":"Failed to enable raw mode: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/tui/src/tui/ui/event_loop.rs","lineNumber":174,"sourceCode":"    // without a controlling TTY (#4716). Without this, enable_raw_mode fails\n    // with opaque \"Device not configured\" / \"Input/output error\" and some\n    // terminal hosts surface only \"[Process completed]\".\n    require_interactive_terminal(io::stdin().is_terminal(), io::stdout().is_terminal())?;\n\n    // Terminal probe with timeout to prevent hanging on unresponsive terminals.\n    //\n    // The blocking task cannot be cancelled once the timeout fires, so a slow\n    // `enable_raw_mode` may still succeed *after* we've bailed out, leaking\n    // raw mode. Both sides run `raw_mode_probe_handshake`; whichever observes\n    // the other's flag disables raw mode again.\n    let probe_timeout = terminal_probe_timeout(config);\n    let probe_abandoned = Arc::new(AtomicBool::new(false));\n    let probe_enabled = Arc::new(AtomicBool::new(false));\n    let task_abandoned = Arc::clone(&probe_abandoned);\n    let task_enabled = Arc::clone(&probe_enabled);\n    let enable_raw = tokio::task::spawn_blocking(move || {\n        let result =\n            enable_raw_mode().map_err(|e| anyhow::anyhow!(\"Failed to enable raw mode: {e}\"));\n        if result.is_ok() && raw_mode_probe_handshake(&task_enabled, &task_abandoned) {\n            // The probe timed out while we were blocked; the caller already\n            // gave up, so undo the late enable instead of leaking raw mode.\n            let _ = disable_raw_mode();\n        }\n        result\n    });\n\n    match tokio::time::timeout(probe_timeout, enable_raw).await {\n        Ok(inner_result) => {\n            inner_result??; // propagate both join and raw-mode errors\n        }\n        Err(_) => {\n            if raw_mode_probe_handshake(&probe_abandoned, &probe_enabled) {\n                // The blocking task finished enabling raw mode right as the\n                // timeout fired and may have missed the abandoned flag.\n                let _ = disable_raw_mode();\n            }","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/tui/ui/event_loop.rs#L156-L192","documentation":"crossterm's enable_raw_mode failed inside the startup probe (run on a spawn_blocking task). The OS error is appended: ENOTTY when stdin is not a terminal, EBADF on closed stdin, or a termios ioctl rejection. Raw mode is a hard prerequisite for the TUI, so startup aborts; sibling code prints guidance to run from an interactive terminal and to use `codewhale exec` for headless prompts.","triggerScenarios":"Launching the TUI with stdin piped, closed, or detached (`codewhale tui < file`, `docker exec` without -t, CI runners), a dead or absent PTY, or another process already owning raw mode on the same TTY.","commonSituations":"Headless invocations of the TUI binary instead of the exec mode; automation wrappers consuming stdin; broken SSH PTY allocation.","solutions":["Run from an interactive terminal: `docker exec -it …`, `ssh -t …`","Do not redirect stdin/stdout when launching the TUI; for headless prompts use `codewhale exec \"…\"`","Verify with the `tty` command - it must print a device path","Ensure no other raw-mode owner holds the terminal"],"exampleFix":"# before\ndocker exec codewhale-container codewhale tui   # stdin not a TTY\n# -> Failed to enable raw mode: … (os error 25)\n\n# after\ndocker exec -it codewhale-container codewhale tui","handlingStrategy":"validation","validationCode":"// Rust - refuse TUI startup without a TTY stdin\nuse std::io::IsTerminal;\nif !std::io::stdin().is_terminal() {\n    eprintln!(\"codewhale tui needs an interactive terminal; use `codewhale exec` for headless prompts\");\n    std::process::exit(1);\n}","typeGuard":null,"tryCatchPattern":"match enable_raw_mode() {\n    Ok(()) => run_tui(),\n    Err(e) => { restore_terminal(); print_run_from_tty_guidance(e); std::process::exit(1); }\n}","preventionTips":["Always allocate a PTY (`docker exec -it`, `ssh -t`) when launching the TUI","Use the headless/exec entry point for automation instead of the TUI binary","Never redirect stdin/stdout when starting the TUI"],"tags":["terminal","raw-mode","tty","stdin","startup"],"backgroundTag":"terminal-raw-mode-failed","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}