aaif-goose/goose · error

Failed to start extension: {}

Error message

Failed to start extension: {}

What it means

add_and_persist_extensions forwards each ExtensionConfig to Agent::add_extension, which spawns the stdio MCP server process. Any startup failure — spawn error, immediate exit, or failed MCP handshake — is wrapped as 'Failed to start extension: {e}' with the underlying cause in the message.

Source

Thrown at crates/goose-cli/src/session/mod.rs:451

                    ExtensionConfig::Builtin {
                        name: extension_name.to_string(),
                        display_name: None,
                        timeout: None,
                        bundled: None,
                        description: extension_name.to_string(),
                        available_tools: Vec::new(),
                    }
                }
            })
            .collect()
    }

    async fn add_and_persist_extensions(&mut self, configs: Vec<ExtensionConfig>) -> Result<()> {
        for config in configs {
            self.agent
                .add_extension(config, &self.session_id)
                .await
                .map_err(|e| anyhow::anyhow!("Failed to start extension: {}", e))?;
        }

        self.invalidate_completion_cache().await;

        Ok(())
    }

    pub async fn add_extension(&mut self, extension_command: String) -> Result<()> {
        let config = Self::parse_stdio_extension(&extension_command)?;
        self.add_and_persist_extensions(vec![config]).await
    }

    pub async fn add_streamable_http_extension(&mut self, extension_url: String) -> Result<()> {
        let config = Self::parse_streamable_http_extension(
            &extension_url,
            goose::config::DEFAULT_EXTENSION_TIMEOUT,
        );
        self.add_and_persist_extensions(vec![config]).await

View on GitHub (pinned to 3810898a74)

Solutions

  1. Run the extension command by hand in the same shell and confirm it starts and stays up
  2. Install the missing runtime or package dependencies the command needs
  3. Use an absolute path for the command when PATH resolution differs
  4. Re-add the extension with corrected KEY=VALUE env prefixes

Example fix

# before
--with-extension my-mcp-server            # not on PATH
# after
--with-extension node /home/me/my-mcp-server/build/index.js
Defensive patterns

Strategy: validation

Validate before calling

use std::process::Command;

fn extension_command_runs(cmd: &str) -> bool {
    let mut parts = cmd.split_whitespace();
    match parts.next() {
        Some(bin) => Command::new(bin).output().is_ok(),
        None => false,
    }
}

Try / catch

if let Err(e) = session.add_extension(cmd.to_string()).await {
    if e.to_string().contains("Failed to start extension") {
        eprintln!("extension '{}' failed to start; check PATH and dependencies", cmd);
    }
    return Err(e);
}

Prevention

When it happens

Trigger: goose add-extension / --with-extension with a command not on PATH, not executable, missing its runtime (node/python), or an MCP server that crashes before the initialize handshake completes.

Common situations: Wrong interpreter path; node_modules missing after a fresh clone; PATH differing between the user's shell and goose's environment; npx fetch failures offline.

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/a21df8d2f31a6cc4. Report an issue: GitHub.