zeroclaw-labs/zeroclaw · error · anyhow::Error

ACP elicitation/create timed out after {timeout:?}

Error message

ACP elicitation/create timed out after {timeout:?}

What it means

The client never answered the elicitation/create request within the caller-supplied timeout. ZeroClaw wraps every elicitation call in tokio::time::timeout so an unresponsive client (user walked away, IDE closed, transport stalled) cannot park the agent turn forever. The elapsed Duration is included in the message.

Source

Thrown at crates/zeroclaw-channels/src/acp_channel.rs:152

        let req = ElicitationRequest {
            session_id: self.session_id.clone(),
            mode: ElicitationMode::Form,
            message: question.to_string(),
            requested_schema: single_select_schema(choices),
        };
        debug_assert!(
            matches!(req.mode, ElicitationMode::Form),
            "Phase 1 must not emit URL-mode elicitation"
        );

        let params = serde_json::to_value(&req)?;
        let call = self.rpc.request("elicitation/create", params);
        let response_value = match tokio::time::timeout(timeout, call).await {
            Ok(Ok(value)) => value,
            Ok(Err(e)) => {
                anyhow::bail!("ACP elicitation/create failed: {} ({})", e.message, e.code)
            }
            Err(_) => anyhow::bail!("ACP elicitation/create timed out after {timeout:?}"),
        };

        let parsed: ElicitationResponse = serde_json::from_value(response_value)
            .map_err(|e| anyhow::Error::msg(format!("malformed elicitation response: {e}")))?;
        match parsed {
            ElicitationResponse::Accept { content } => {
                let text =
                    zeroclaw_api::elicitation::decode_single_select_accept(&content, choices)?;
                Ok(Some(text))
            }
            ElicitationResponse::Decline | ElicitationResponse::Cancel => Ok(None),
        }
    }
}

impl ::zeroclaw_api::attribution::Attributable for AcpChannel {
    fn role(&self) -> ::zeroclaw_api::attribution::Role {
        ::zeroclaw_api::attribution::Role::Channel(

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Raise the timeout passed to request_choice to comfortably exceed expected human response time (minutes, not seconds, for interactive prompts).
  2. Verify the ACP client process and transport are alive; a dead back channel can never deliver a response.
  3. Treat this error as a cancellation (None) in the caller so the agent proceeds without user input instead of failing.
  4. If prompts routinely expire, pre-ask availability or route the question through a channel with push notifications.

Example fix

// before
let pick = ch.request_choice("Deploy to prod?", &choices, Duration::from_secs(10)).await?;

// after
let pick = match ch.request_choice("Deploy to prod?", &choices, Duration::from_secs(300)).await {
    Ok(opt) => opt,
    Err(e) if e.to_string().contains("timed out") => {
        tracing::warn!(error = %e, "no answer in time; treating as cancel");
        None
    }
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: retry

Try / catch

match ch.request_choice(q, &choices, timeout).await {
    Ok(opt) => opt,
    Err(e) if e.to_string().contains("timed out") => {
        // one re-ask, then treat as user cancel
        ch.request_choice(q, &choices, timeout).await.unwrap_or(None)
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: request_choice takes the elicitation path and no JSON-RPC response arrives before the Duration passed to request_choice elapses — the user leaves the form open, the client process exits without cancelling, or the back channel silently dies.

Common situations: Timeouts sized for network round-trips instead of human response time; modal dialogs hidden behind other windows; laptop sleep mid-prompt; dead stdio/WebSocket transport that never delivers the response.

Understand the failure class

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/afb531c64599253e. Report an issue: GitHub.