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
- Raise the timeout passed to request_choice to comfortably exceed expected human response time (minutes, not seconds, for interactive prompts).
- Verify the ACP client process and transport are alive; a dead back channel can never deliver a response.
- Treat this error as a cancellation (None) in the caller so the agent proceeds without user input instead of failing.
- 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
- Size prompt timeouts for human response time, not network time
- Cancel in-flight prompts on session/stop so timeouts do not race teardown
- Distinguish timeout (retry or default) from transport failure (surface immediately)
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
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- ACP elicitation/create failed: {} ({})
- ACP elicitation/create (multi) timed out after {timeout:?}
- ACP returned unexpected outcome: {other}
- AcpChannel.request_choice requires at least one choice
- ACP elicitation/create (multi) failed: {} ({})
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/afb531c64599253e.
Report an issue: GitHub.