Hmbown/CodeWhale · error
Codewhale TUI could not verify foreground terminal ownership
Error message
Codewhale TUI could not verify foreground terminal ownership: {os_error} What it means
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.
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)
Defensive patterns
Strategy: try-catch
Validate before calling
let pgid = unsafe { libc::tcgetpgrp(libc::STDIN_FILENO) };
if pgid < 0 { eprintln!("no controlling terminal: {}", std::io::Error::last_os_error()); } Try / catch
match codew::launch() {
Err(e) if e.to_string().contains("foreground terminal ownership") => {
eprintln!("launch from a terminal with a controlling tty");
}
other => other?,
} Prevention
- 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)
When it happens
Trigger: 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.
Common situations: Launching codew from a daemon or container without a controlling tty; unusual terminal multiplexer setups; file-descriptor juggling in wrappers.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- Codewhale TUI cannot start from a background or suspended…
- Codewhale TUI could not verify foreground terminal ownership
- Codewhale TUI requires an interactive terminal (stdin and…
- Failed to enable raw mode
- OSC 52 clipboard fallback requires a terminal
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/d73ba12b191cf12f.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tui/ui/terminal.rs:128
or `codewhale` there — not from a pipe, cron job, or non-TTY launcher.\n\
For headless prompts use `codewhale exec \"…\"` instead."
))
}
/// Refuse to enter terminal modes from a background Unix process group.
///
/// A TTY can still report `isatty(3) == true` after a shell has suspended the
/// process. Reading from that background group triggers `SIGTTIN`; enabling
/// mouse or keyboard protocols before that stop poisons the shell with raw
/// escape reports. Check foreground ownership before the first mode change.
#[cfg(unix)]
pub(crate) fn require_foreground_terminal_owner() -> Result<()> {
// SAFETY: both calls are read-only process/terminal queries on the
// controlling stdin descriptor and require no borrowed memory.
let (terminal_pgid, process_pgid) =
unsafe { (libc::tcgetpgrp(libc::STDIN_FILENO), libc::getpgrp()) };
if terminal_pgid < 0 {
return Err(anyhow::anyhow!(
"Codewhale TUI could not verify foreground terminal ownership: {}",
io::Error::last_os_error()
));
}
validate_foreground_process_group(terminal_pgid, process_pgid)
}
#[cfg(not(unix))]
pub(crate) fn require_foreground_terminal_owner() -> Result<()> {
Ok(())
}
#[cfg(unix)]
pub(crate) fn validate_foreground_process_group(
terminal_pgid: libc::pid_t,
process_pgid: libc::pid_t,
) -> Result<()> {
if terminal_pgid == process_pgid {View on GitHub (pinned to 433685b202)