{"record":{"id":"d73ba12b191cf12f","repo":"Hmbown/CodeWhale","slug":"codewhale-tui-could-not-verify-foreground-terminal-ownership","errorCode":null,"errorMessage":"Codewhale TUI could not verify foreground terminal ownership: {os_error}","messagePattern":"Codewhale TUI could not verify foreground terminal ownership: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/ui/terminal.rs","lineNumber":128,"sourceCode":"         or `codewhale` there — not from a pipe, cron job, or non-TTY launcher.\\n\\\n         For headless prompts use `codewhale exec \\\"…\\\"` instead.\"\n    ))\n}\n\n/// Refuse to enter terminal modes from a background Unix process group.\n///\n/// A TTY can still report `isatty(3) == true` after a shell has suspended the\n/// process. Reading from that background group triggers `SIGTTIN`; enabling\n/// mouse or keyboard protocols before that stop poisons the shell with raw\n/// escape reports. Check foreground ownership before the first mode change.\n#[cfg(unix)]\npub(crate) fn require_foreground_terminal_owner() -> Result<()> {\n    // SAFETY: both calls are read-only process/terminal queries on the\n    // controlling stdin descriptor and require no borrowed memory.\n    let (terminal_pgid, process_pgid) =\n        unsafe { (libc::tcgetpgrp(libc::STDIN_FILENO), libc::getpgrp()) };\n    if terminal_pgid < 0 {\n        return Err(anyhow::anyhow!(\n            \"Codewhale TUI could not verify foreground terminal ownership: {}\",\n            io::Error::last_os_error()\n        ));\n    }\n    validate_foreground_process_group(terminal_pgid, process_pgid)\n}\n\n#[cfg(not(unix))]\npub(crate) fn require_foreground_terminal_owner() -> Result<()> {\n    Ok(())\n}\n\n#[cfg(unix)]\npub(crate) fn validate_foreground_process_group(\n    terminal_pgid: libc::pid_t,\n    process_pgid: libc::pid_t,\n) -> Result<()> {\n    if terminal_pgid == process_pgid {","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/tui/src/tui/ui/terminal.rs#L110-L146","documentation":"Thrown by require_foreground_terminal_owner when libc::tcgetpgrp on stdin returns a negative value, meaning the foreground process group of the controlling terminal could not be queried. The launcher refuses to continue because it cannot verify it owns the terminal, and the OS error is embedded for diagnosis. This is a safety check before claiming terminal control.","triggerScenarios":"Running with stdin detached from a controlling terminal (no ctty); a corrupted/odd pty setup; restricted sandbox or container where tcgetpgrp fails; stdin redirected to a file or pipe so there is no terminal to query.","commonSituations":"Launching codew from a daemon or container without a controlling tty; unusual terminal multiplexer setups; file-descriptor juggling in wrappers.","solutions":["Run codew from a terminal that is actually its controlling terminal (fresh shell)","If in a container/service, allocate a pty (e.g. `script -qc` or docker -t)","Check the embedded OS error (errno) for the specific failure (e.g. ENOTTY, ENXIO)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"let pgid = unsafe { libc::tcgetpgrp(libc::STDIN_FILENO) };\nif pgid < 0 { eprintln!(\"no controlling terminal: {}\", std::io::Error::last_os_error()); }","typeGuard":null,"tryCatchPattern":"match codew::launch() {\n    Err(e) if e.to_string().contains(\"foreground terminal ownership\") => {\n        eprintln!(\"launch from a terminal with a controlling tty\");\n    }\n    other => other?,\n}","preventionTips":["Launch from a shell with a controlling terminal","Avoid daemons/wrappers that detach fd 0 from the ctty","Allocate a pty in containers (docker -t, script -qc)"],"tags":["terminal","process-group","tty"],"backgroundTag":"permission-denied","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}