aaif-goose/goose · critical · anyhow::Error
{e}
Error message
{e} What it means
The error body is the raw message from spawn_acp_process ('failed to spawn ACP process' plus OS detail), forwarded over the init channel so the ACP provider's initialize future fails instead of hanging. spawn_acp_process builds the child command from config.command/config.args with piped stdio, prepends the command's parent dir to PATH (for npm adapters), applies env_remove/env, then calls cmd.spawn() — so this error means the process itself never started.
Source
Thrown at crates/goose/src/acp/provider.rs:886
) -> Self {
Self {
config,
goose_mode,
prompt_response_tx: Arc::new(Mutex::new(None)),
pending_tool_updates,
context_size,
}
}
async fn spawn(
self,
mut rx: mpsc::Receiver<ClientRequest>,
init_tx: oneshot::Sender<Result<InitializeResponse>>,
) {
let child = match spawn_acp_process(&self.config).await {
Ok(c) => c,
Err(e) => {
let _ = init_tx.send(Err(anyhow::anyhow!("{e}")));
tracing::error!("failed to spawn ACP process: {e}");
return;
}
};
match self.run_with_child(child, &mut rx, init_tx).await {
Ok(()) => tracing::debug!("ACP protocol loop exited cleanly"),
Err(e) => tracing::error!(error = %e, "ACP protocol loop error"),
}
}
async fn run_with_child(
self,
mut child: Child,
rx: &mut mpsc::Receiver<ClientRequest>,
init_tx: oneshot::Sender<Result<InitializeResponse>>,
) -> Result<()> {
let stdin = child.stdin.take().context("no stdin")?;View on GitHub (pinned to 3810898a74)
Solutions
- Verify the binary resolves and runs in the same context: 'which <command>' and execute it manually with the configured args
- Use an absolute path for config.command (e.g. /usr/local/bin/my-agent or the real path under node_modules/.bin)
- Ensure the file is executable and, for scripts, has a valid shebang (chmod +x, #!/usr/bin/env node)
- Install the missing agent package or point config.command at the correct installed location
Example fix
# before command: my-acp-agent args: [] # after command: /home/user/.npm-global/bin/my-acp-agent args: []
Defensive patterns
Strategy: validation
Validate before calling
use std::path::Path;
use which::which; // or manual PATH scan
fn agent_command_available(command: &str) -> bool {
command.contains('/') && Path::new(command).is_file()
|| which(command).is_ok()
}
assert!(
agent_command_available(&config.command),
"ACP agent command '{}' not found; install it or use an absolute path",
config.command
); Try / catch
match provider.initialize().await {
Ok(_) => {}
Err(e) if e.to_string().contains("failed to spawn ACP process") => {
eprintln!("agent binary missing or not executable: {e}");
std::process::exit(127); // command-not-found convention, no retry
}
Err(e) => return Err(e),
} Prevention
- Prefer absolute paths for config.command
- Smoke-test the agent command with its args before wiring it into goose
- For npm-based agents, install globally and point at the real bin path
When it happens
Trigger: config.command points to a binary that does not exist (ENOENT), is not executable (EACCES), is a directory, or PATH lookup fails because the command lives in a directory absent from PATH and has no explicit parent dir (e.g. bare 'node' resolved from a GUI environment whose PATH omits it).
Common situations: Using an ACP agent installed via npx/pnpm where the bin dir is not on the desktop app's PATH, a typo in the command path, a script missing its shebang or execute bit, or running on a machine where the agent was never installed.
Related errors
- ACP agent rejected session/set_config_option for '{}': {err}
- Requested mode(s) [{}] not offered by agent. Available modes
- ACP URL is not available
- Message with id ${messageId} not found in current messages
- Cannot update message while prompt is active
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/3b72647a4c563cb4.
Report an issue: GitHub.