aaif-goose/goose · critical · anyhow::Error

ACP initialize failed: {err}

Error message

ACP initialize failed: {err}

What it means

The JSON-RPC 'initialize' request to the ACP agent failed at the protocol layer. The request is sent with ProtocolVersion::LATEST and the client capabilities right after the child spawns; failure means the agent process answered with an error, closed the connection, or the transport broke before/while responding. The message is both returned as the init error and surfaced to the caller as an internal_error.

Source

Thrown at crates/goose/src/acp/provider.rs:1254

    cx: ConnectionTo<Agent>,
    rx: &mut mpsc::Receiver<ClientRequest>,
    prompt_response_tx: Arc<Mutex<Option<mpsc::Sender<AcpUpdate>>>>,
    init_tx: oneshot::Sender<Result<InitializeResponse>>,
) -> Result<(), agent_client_protocol::Error> {
    let mut init_tx = Some(init_tx);

    let client_capabilities = ClientCapabilities::new();
    let init_response: InitializeResponse = cx
        .send_request(
            InitializeRequest::new(ProtocolVersion::LATEST)
                .client_capabilities(client_capabilities),
        )
        .block_task()
        .await
        .map_err(|err| {
            let message = format!("ACP {} failed: {err}", AGENT_METHOD_NAMES.initialize);
            if let Some(tx) = init_tx.take() {
                let _ = tx.send(Err(anyhow::anyhow!(message.clone())));
            }
            agent_client_protocol::Error::internal_error().data(message)
        })?;

    let supports_close = init_response
        .agent_capabilities
        .session_capabilities
        .close
        .is_some();
    let supports_load = init_response.agent_capabilities.load_session;
    let mcp_capabilities = init_response.agent_capabilities.mcp_capabilities.clone();
    if let Some(tx) = init_tx.take() {
        log_undelivered(tx.send(Ok(init_response)), AGENT_METHOD_NAMES.initialize);
    }

    let mut session_ids: Vec<SessionId> = Vec::new();

    while let Some(request) = rx.recv().await {

View on GitHub (pinned to 3810898a74)

Solutions

  1. Run the agent command manually with the same args/env and watch stderr; ensure nothing but JSON-RPC goes to stdout (route logs to stderr)
  2. For npx-based agents, pre-install the package (npm i -g) so first-run download output cannot corrupt the stream
  3. Align versions: update goose and the agent so both use a compatible agent-client-protocol crate
  4. Set any env vars the agent requires at startup via the provider's env map

Example fix

# before (agent code pollutes stdout)
console.log('agent starting');

# after
console.error('agent starting');
Defensive patterns

Strategy: try-catch

Try / catch

match provider.initialize().await {
    Ok(resp) => resp,
    Err(e) if e.to_string().contains("initialize") => {
        tracing::error!(%e, "ACP agent failed to initialize; check agent stderr and stdout hygiene");
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: The agent process prints non-protocol text to stdout (banners, logs, compile output) corrupting the JSON-RPC stream; the agent exits or crashes immediately after spawn (bad args, missing runtime like an unavailable node version); a protocol version or schema mismatch between goose and the agent.

Common situations: Wrapping a CLI that logs to stdout instead of stderr, npx downloading/caching output polluting stdout on first run, agent built against an older agent_client_protocol version, or the agent exiting due to a missing env var needed at startup.

Related errors


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