zeroclaw-labs/zeroclaw · error

RPC elicitation/create failed: {} ({})

Error message

RPC elicitation/create failed: {} ({})

What it means

request_choice_via_elicitation implements approval prompts over RPC: it serializes an ElicitationRequest (form mode, single-select schema) and calls rpc.request("elicitation/create", ...). If the RPC call itself completes with an error — as opposed to timing out, which is error 879 — it bails with the transport error's message and code. Root causes live on the RPC/client side: connection dropped mid-call, method unsupported by the connected client, or protocol-level rejection.

Source

Thrown at crates/zeroclaw-runtime/src/rpc/approval_channel.rs:237

        choices: &[String],
        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!("RPC elicitation/create failed: {} ({})", e.message, e.code)
            }
            Err(_) => anyhow::bail!("RPC 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 = decode_single_select_accept(&content, choices)?;
                Ok(Some(text))
            }
            ElicitationResponse::Decline | ElicitationResponse::Cancel => Ok(None),
        }
    }

    /// Form-mode elicitation multi-select path — same wire shape as
    /// `AcpChannel::request_multi_choice`.
    async fn request_multi_choice_via_elicitation(
        &self,

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Classify by the embedded (code): connection-closed codes mean the client went away — retry only after reconnect; unknown-method codes mean the client lacks elicitation support — upgrade the client/daemon pair
  2. Upgrade both sides so the client speaks the same elicitation/create RPC version
  3. Verify the session id passed to the approval channel is the live session
  4. Handle the failure as an unanswered prompt: fall back to deny/default (the surrounding channel code already maps unreachable clients to Deny for other paths)

Example fix

// before
let choice = channel.request_choice(&q, &choices, timeout).await?;

// after
match channel.request_choice(&q, &choices, timeout).await {
    Ok(Some(c)) => c,
    Ok(None) => default_choice(),            // declined/cancelled
    Err(e) if e.to_string().contains("elicitation/create failed") => {
        tracing::warn!("client unreachable: {e}");
        default_choice()                     // treat as deny/default
    }
    Err(e) => return Err(e),
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before prompting, confirm the RPC peer is alive and speaks elicitation
if !rpc.connected() { return Ok(default_choice()); }
// optionally negotiate capabilities at session start and cache `supports_elicitation`

Try / catch

match channel.request_choice(&q, &choices, timeout).await {
    Ok(Some(c)) => c,
    Ok(None) => default_choice(),
    Err(e) if e.to_string().contains("elicitation/create failed") => {
        // client-side RPC failure: classify by the embedded code; treat as unanswered → deny/default
        default_choice()
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: The connected client (IDE/editor/host) disconnects while the approval prompt is pending; the client predates the elicitation/create method so the peer returns a method-not-found style error; serialization/session problems such as an invalid session_id in the request; the RPC channel was already closed during shutdown, so the request errors instead of hanging.

Common situations: Operator closes their client right when a sensitive action asks for approval; version skew between daemon and client after a partial upgrade; sessions expiring server-side between the call and the response; test harnesses with stub RPC peers that error on unknown methods.

Related errors


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