{"record":{"id":"286bf161c3820d60","repo":"denisidoro/navi","slug":"not-enough-data","errorCode":null,"errorMessage":"Not enough data","messagePattern":"Not enough data","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/common/terminal.rs","lineNumber":31,"sourceCode":"            .arg(\"size\")\n            .stderr(Stdio::inherit())\n            .output()?\n    } else {\n        Command::new(\"stty\")\n            .arg(\"size\")\n            .arg(\"-F\")\n            .arg(\"/dev/stderr\")\n            .stderr(Stdio::inherit())\n            .output()?\n    };\n\n    if let Some(0) = output.status.code() {\n        let stdout = String::from_utf8(output.stdout).expect(\"Invalid utf8 output from stty\");\n        let mut data = stdout.split_whitespace();\n        data.next();\n        return data\n            .next()\n            .expect(\"Not enough data\")\n            .parse::<u16>()\n            .map_err(|_| anyhow!(\"Invalid width\"));\n    }\n\n    Err(anyhow!(\"Invalid status code\"))\n}\n\npub fn width() -> u16 {\n    if let Ok((w, _)) = terminal::size() {\n        w\n    } else {\n        width_with_shell_out().unwrap_or(FALLBACK_WIDTH)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/denisidoro/navi/blob/f7330b9ad5bd95b7d1a3c96d00e0a77deb589147/src/common/terminal.rs#L13-L49","documentation":"This panic comes from an `.expect(\"Not enough data\")` on an iterator item in `width_with_shell_out` (src/common/terminal.rs:31). The function shells out to `stty size`, which prints '<rows> <cols>' on stdout; the code skips the first whitespace-separated token and expects a second token (the column count). If `stty` exits 0 but prints fewer than two tokens (or nothing), the iterator is exhausted and the expect panics. It is a hard panic, not a Result error, though the caller `width()` would have fallen back to 80 columns if it were propagated as an Err.","triggerScenarios":"`stty` is executed with exit code 0 but its stdout does not contain two whitespace-separated fields — e.g. stdout is empty, or contains only a row count — while the crossterm `terminal::size()` path has already failed (no real TTY). This can happen with unusual/patched stty builds, locale wrappers that emit extra warnings (only if they consume stdout), stubbed stty binaries in CI containers, or pseudo-terminal setups where stty reports success but no size.","commonSituations":"Running inside Docker/CI where stderr is redirected to a non-tty and an stty shim returns 0 with empty output; environments with a fake or busybox `stty` that behaves differently from GNU/coreutils stty; terminal multiplexers or wrappers that break crossterm's ioctl and then also break the stty fallback; SSH sessions with a broken PTY allocation.","solutions":["Ensure the process runs with a real TTY on stderr (allocate a PTY, e.g. `ssh -t`, `script -qec`, or a Docker `-t` flag) so both crossterm and stty can report a size","Verify `stty -F /dev/stderr size` (or `stty -f /dev/stderr size` on macOS) prints two numbers in your environment; fix or remove broken stty shims from PATH","Upgrade the library / patch `width_with_shell_out` to check `data.next()` and return `Err(anyhow!(\"Not enough data\"))` instead of panicking, so the existing FALLBACK_WIDTH=80 path applies","As a workaround, force a known terminal size in CI (e.g. `stty cols 80 rows 24` or `COLUMNS=80`) before invoking"],"exampleFix":"// before\nreturn data\n    .next()\n    .expect(\"Not enough data\")\n    .parse::<u16>()\n    .map_err(|_| anyhow!(\"Invalid width\"));\n// after\nreturn data\n    .next()\n    .ok_or_else(|| anyhow!(\"Not enough data\"))?\n    .parse::<u16>()\n    .map_err(|_| anyhow!(\"Invalid width\"));","handlingStrategy":"fallback","validationCode":"// Run before relying on the shell-out path:\nuse std::process::Command;\nfn stty_output_ok() -> bool {\n    let out = Command::new(\"stty\").arg(\"size\").arg(\"-F\").arg(\"/dev/stderr\")\n        .output().ok();\n    match out {\n        Some(o) if o.status.code() == Some(0) => {\n            let s = String::from_utf8_lossy(&o.stdout);\n            s.split_whitespace().count() >= 2\n                && s.split_whitespace().nth(1).unwrap().parse::<u16>().is_ok()\n        }\n        _ => false,\n    }\n}","typeGuard":"fn valid_stty_size(stdout: &str) -> Option<u16> {\n    let mut it = stdout.split_whitespace();\n    it.next()?; // rows\n    it.next()?.parse::<u16>().ok() // columns\n}","tryCatchPattern":"// In Rust, prefer not panicking: change the expect to Result and rely on\n// width()'s existing fallback (this library already falls back to 80):\nmatch std::panic::catch_unwind(width_with_shell_out) {\n    Ok(w) => w,\n    Err(_) => 80, // FALLBACK_WIDTH\n}","preventionTips":["Always run the tool with a real TTY on stderr; in CI allocate a PTY (docker -t, ssh -t, script -qec)","Sanity-check `stty -F /dev/stderr size` output in new environments (containers, SSH, multiplexers) before deploying","Remove or fix stty shims/wrappers from PATH that exit 0 without printing '<rows> <cols>'","Prefer the library's own fallback: assume width 80 is used when no TTY exists rather than forcing the shell-out path"],"tags":["panic","terminal","stty","tty","unexpected-unwrap"],"backgroundTag":"unexpected-unwrap-panic","analyzedSha":"f7330b9ad5bd95b7d1a3c96d00e0a77deb589147","analyzedAt":"2026-09-03T13:58:22.429Z","contentChangedAt":"2026-09-03T13:58:22.429Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}