{"record":{"id":"63c078f1479b98d0","repo":"svenstaro/genact","slug":"couldn-t-get-terminal-width-is-an-interactive-ter","errorCode":null,"errorMessage":"Couldn't get terminal width. Is an interactive terminal attached?","messagePattern":"Couldn't get terminal width\\. Is an interactive terminal attached\\?","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/io.rs","lineNumber":117,"sourceCode":"\npub async fn cursor_up(n: u64) {\n    print(format!(\"\\x1b[{n}A\")).await;\n}\n\n// pub async fn cursor_left(n: u64) {\n//     print(format!(\"\\x1b[{}D\", n)).await;\n// }\n\npub async fn erase_line() {\n    print(\"\\x1b[2K\\x1b[0G\").await;\n}\n\n#[cfg(not(target_arch = \"wasm32\"))]\npub fn get_terminal_width() -> usize {\n    if let Some((width, _)) = terminal_size::terminal_size() {\n        width.0.into()\n    } else {\n        panic!(\"Couldn't get terminal width. Is an interactive terminal attached?\")\n    }\n}\n\n#[cfg(target_arch = \"wasm32\")]\n#[wasm_bindgen(inline_js = \"export function get_terminal_width() { return window.xterm.cols }\")]\nextern \"C\" {\n    pub fn get_terminal_width() -> usize;\n}\n","sourceCodeStart":99,"sourceCodeEnd":126,"githubUrl":"https://github.com/svenstaro/genact/blob/858be63ad272ce0d451d2a7f6c075c15998c12ec/src/io.rs#L99-L126","documentation":"get_terminal_width() queries the terminal size via terminal_size::terminal_size(), and panics when it cannot determine a width. The function assumes a TTY (or on wasm32, a fake window.xterm) is attached; when stdout/stderr is not an interactive terminal (no ioctl TIOCGWINSZ data), the library deliberately panics rather than return a guessed width. It is called from run() to lay out progress/output formatting.","triggerScenarios":"Calling run() (which calls get_terminal_width()) in an environment where terminal_size::terminal_size() returns None: piping output to a file or another program, running under CI (no TTY), running in a non-interactive ssh/exec context, or a WSL/dumb terminal that does not report size.","commonSituations":"CI pipelines (GitHub Actions, GitLab CI) where stdout is a pipe; `cargo run | tee log.txt`; docker run without -t; background jobs or systemd services with no controlling terminal; IDE run consoles that are not real PTYs.","solutions":["Run the program in an interactive terminal (attach a TTY: docker run -t, ssh -t, script -qec '...')","Redirect output only for files while keeping stderr on a TTY, or use a pty wrapper (e.g. `script -c 'myapp'`)","Patch/wrap get_terminal_width to fall back to a default width (e.g. 80) instead of panicking when no TTY is present","Skip interactive rendering paths in run() when !atty/is-terminal detects a non-TTY stdout"],"exampleFix":"// before\npub fn get_terminal_width() -> usize {\n    if let Some((width, _)) = terminal_size::terminal_size() {\n        width.0.into()\n    } else {\n        panic!(\"Couldn't get terminal width. Is an interactive terminal attached?\")\n    }\n}\n// after\npub fn get_terminal_width() -> usize {\n    terminal_size::terminal_size()\n        .map(|(w, _)| w.0 as usize)\n        .unwrap_or(80)\n}","handlingStrategy":"fallback","validationCode":"let has_tty = std::io::IsTerminal::is_terminal(&std::io::stdout());\nlet width: usize = if has_tty {\n    terminal_size::terminal_size().map(|(w, _)| w.0 as usize).unwrap_or(80)\n} else {\n    80\n};","typeGuard":"fn terminal_available() -> bool {\n    use std::io::IsTerminal;\n    std::io::stdout().is_terminal() && terminal_size::terminal_size().is_some()\n}","tryCatchPattern":"// Rust panics cannot be caught with try/catch; either pre-check with terminal_available()\n// or catch the unwind:\nlet width = std::panic::catch_unwind(get_terminal_width)\n    .unwrap_or(80);","preventionTips":["Check std::io::stdout().is_terminal() before calling run()","Provide a default width (80/120) when no TTY exists","Test the program with output piped (`| cat`) and under CI before release","Use docker run -t or script -c when a PTY is required"],"tags":["terminal","tty","panic","io","rust"],"backgroundTag":"unsupported-platform","analyzedSha":"858be63ad272ce0d451d2a7f6c075c15998c12ec","analyzedAt":"2026-09-08T03:43:15.281Z","contentChangedAt":"2026-09-08T03:43:15.281Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}