aaif-goose/goose · error
failed to exec TUI ({descriptor}): {err}
Error message
failed to exec TUI ({descriptor}): {err} What it means
On unix the TUI launcher uses Command::exec, which replaces the goose process with node/npx; exec only RETURNS when it fails. So this message always carries a raw OS error: usually NotFound (node or npx missing from PATH), NoSuchFile (local TUI script path wrong), or PermissionDenied. The descriptor names exactly what was exec'd (node <script> or npx --package <spec>).
Source
Thrown at crates/goose-cli/src/commands/tui.rs:83
pub fn handle_tui(args: Vec<String>) -> Result<()> {
let source = resolve_source();
let goose_binary = std::env::current_exe()
.context("could not determine current goose executable to expose as GOOSE_BINARY")?;
let mut cmd = build_command(&source, &args)?;
cmd.env("GOOSE_BINARY", &goose_binary);
let descriptor = match &source {
TuiSource::LocalScript(p) => format!("node {}", p.display()),
TuiSource::Npx(spec) => format!("npx --package {} -- {}", spec, NPM_BIN_NAME),
};
#[cfg(unix)]
{
use std::os::unix::process::CommandExt;
let err = cmd.exec();
Err(anyhow!("failed to exec TUI ({descriptor}): {err}"))
}
#[cfg(not(unix))]
{
let status = cmd
.status()
.with_context(|| format!("failed to run `{descriptor}`"))?;
if !status.success() {
std::process::exit(status.code().unwrap_or(1));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;View on GitHub (pinned to 3810898a74)
Solutions
- Run the descriptor command yourself (e.g. `node --version`, `npx --version`) to reproduce the exact OS error
- Install Node.js or fix PATH so node/npx resolve in goose's environment
- For a local script source, verify the path exists and has execute permission
- If behind a proxy, ensure npm/npx can fetch the TUI package
Example fix
# before goose tui # failed to exec TUI (npx --package @block/goose-tui -- goose-tui): No such file or directory # after which node npx # both must resolve export PATH="$HOME/.nvm/versions/node/v22/bin:$PATH" goose tui
Defensive patterns
Strategy: validation
Validate before calling
let node_ok = std::process::Command::new("node")
.arg("--version")
.output()
.map(|o| o.status.success())
.unwrap_or(false);
if !node_ok {
anyhow::bail!("node not available on PATH; install Node.js before launching the TUI");
} Type guard
fn node_available() -> bool {
std::process::Command::new("node")
.arg("--version")
.output()
.map(|o| o.status.success())
.unwrap_or(false)
} Try / catch
match run_tui(source, args).await {
Err(e) if e.to_string().contains("failed to exec TUI") => {
if e.to_string().contains("NotFound") || e.to_string().contains("No such file") {
// node/npx missing from PATH: surface an install hint
}
Err(e)
}
other => other,
} Prevention
- Pre-flight `node --version` and `npx --version` before launching the TUI
- Launch goose from a login shell so PATH matches the environment you tested
- Pin --tui-source to an existing script path and check it at startup
When it happens
Trigger: `goose tui` / TUI launch with Node.js not installed or not on PATH for the goose process; --tui-source pointing at a moved/deleted script; script lacking execute permission; npx wrapper unavailable.
Common situations: Minimal containers/servers without node; PATH differing between login shell and the environment goose runs in (launchers, service managers); stale local TUI path after moving the repo.
Related errors
- GOOSE_BINARY is only supported in development builds
- Invalid GOOSE_BINARY path: ${pathFromEnv} (pwd is ${process.
- goose serve did not become ready on ${statusUrl}.${exitDetai
- GOOSE_SERVER__SECRET_KEY must be set when using GOOSE_EXTERN
- No goose binary available for ${key}. Set GOOSE_BINARY to th
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/710bcdb4da133e4a.
Report an issue: GitHub.