zeroclaw-labs/zeroclaw · error · anyhow::Error
ACP elicitation/create failed: {} ({})
Error message
ACP elicitation/create failed: {} ({}) What it means
The JSON-RPC request elicitation/create itself returned an error response (message + code) instead of a result. This is the form-mode path used when the client advertises clientCapabilities.elicitation.form; the code and message embedded in the error come straight from the client, so they state why the elicitation was refused (method not implemented, invalid params, unknown sessionId).
Source
Thrown at crates/zeroclaw-channels/src/acp_channel.rs:150
timeout: Duration,
) -> anyhow::Result<Option<String>> {
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 {View on GitHub (pinned to 88bb9c8533)
Solutions
- Read the (code, message) pair embedded in the error text — it is the client's own stated reason for the refusal.
- Verify the session still exists on the client; re-run session/new and retry with a fresh sessionId if the client restarted.
- Confirm the client genuinely implements elicitation/create; if not, stop advertising elicitation.form so the legacy permission path is used.
- Align ZeroClaw and the client on protocol revisions that agree on the elicitation schema.
Defensive patterns
Strategy: try-catch
Type guard
fn client_supports_form_elicitation(caps: &ElicitationCapabilities) -> bool {
caps.form
} Try / catch
if let Err(e) = ch.request_choice(q, &choices, timeout).await {
if e.to_string().contains("elicitation/create failed") {
// client refused the prompt: re-create the session or surface
// 'could not ask the user' to the agent instead of retrying blindly
}
} Prevention
- Only advertise elicitation.form when elicitation/create is actually implemented
- Re-create the ACP session after client restarts instead of reusing session ids
- Integration-test the requestedSchema round-trip when bumping protocol versions
When it happens
Trigger: AcpChannel::request_choice on a form-capable client where elicitation/create is rejected: the client advertises elicitation.form but does not implement the handler, the sessionId is stale after a client restart, or the single-select requestedSchema fails the client's validation.
Common situations: Capability handshake lying (form advertised, handler missing); session id from a previous connection reused after reconnect; schema-shape drift between the ZeroClaw version emitting requestedSchema and the client version validating it.
Related errors
- ACP returned unexpected outcome: {other}
- ACP elicitation/create timed out after {timeout:?}
- ACP elicitation/create (multi) failed: {} ({})
- AcpChannel.request_choice requires at least one choice
- ACP elicitation/create (multi) timed out after {timeout:?}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/8277a4c8fbd5cdb4.
Report an issue: GitHub.