{"record":{"id":"1de4698ab8813bbe","repo":"zeroclaw-labs/zeroclaw","slug":"rpc-elicitation-create-failed","errorCode":null,"errorMessage":"RPC elicitation/create failed: {} ({})","messagePattern":"RPC elicitation/create failed: (.+?) \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/rpc/approval_channel.rs","lineNumber":237,"sourceCode":"        choices: &[String],\n        timeout: Duration,\n    ) -> anyhow::Result<Option<String>> {\n        let req = ElicitationRequest {\n            session_id: self.session_id.clone(),\n            mode: ElicitationMode::Form,\n            message: question.to_string(),\n            requested_schema: single_select_schema(choices),\n        };\n        debug_assert!(\n            matches!(req.mode, ElicitationMode::Form),\n            \"Phase 1 must not emit URL-mode elicitation\"\n        );\n        let params = serde_json::to_value(&req)?;\n        let call = self.rpc.request(\"elicitation/create\", params);\n        let response_value = match tokio::time::timeout(timeout, call).await {\n            Ok(Ok(value)) => value,\n            Ok(Err(e)) => {\n                anyhow::bail!(\"RPC elicitation/create failed: {} ({})\", e.message, e.code)\n            }\n            Err(_) => anyhow::bail!(\"RPC elicitation/create timed out after {timeout:?}\"),\n        };\n        let parsed: ElicitationResponse = serde_json::from_value(response_value)\n            .map_err(|e| anyhow::Error::msg(format!(\"malformed elicitation response: {e}\")))?;\n        match parsed {\n            ElicitationResponse::Accept { content } => {\n                let text = decode_single_select_accept(&content, choices)?;\n                Ok(Some(text))\n            }\n            ElicitationResponse::Decline | ElicitationResponse::Cancel => Ok(None),\n        }\n    }\n\n    /// Form-mode elicitation multi-select path — same wire shape as\n    /// `AcpChannel::request_multi_choice`.\n    async fn request_multi_choice_via_elicitation(\n        &self,","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/rpc/approval_channel.rs#L219-L255","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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","Upgrade both sides so the client speaks the same elicitation/create RPC version","Verify the session id passed to the approval channel is the live session","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)"],"exampleFix":"// before\nlet choice = channel.request_choice(&q, &choices, timeout).await?;\n\n// after\nmatch channel.request_choice(&q, &choices, timeout).await {\n    Ok(Some(c)) => c,\n    Ok(None) => default_choice(),            // declined/cancelled\n    Err(e) if e.to_string().contains(\"elicitation/create failed\") => {\n        tracing::warn!(\"client unreachable: {e}\");\n        default_choice()                     // treat as deny/default\n    }\n    Err(e) => return Err(e),\n}","handlingStrategy":"try-catch","validationCode":"// before prompting, confirm the RPC peer is alive and speaks elicitation\nif !rpc.connected() { return Ok(default_choice()); }\n// optionally negotiate capabilities at session start and cache `supports_elicitation`","typeGuard":null,"tryCatchPattern":"match channel.request_choice(&q, &choices, timeout).await {\n    Ok(Some(c)) => c,\n    Ok(None) => default_choice(),\n    Err(e) if e.to_string().contains(\"elicitation/create failed\") => {\n        // client-side RPC failure: classify by the embedded code; treat as unanswered → deny/default\n        default_choice()\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Upgrade daemon and client together to keep elicitation/create versions aligned","Handle client-gone as a normal deny path, matching the channel's Unreachable→Deny semantics","Negotiate client capabilities at connect time and skip elicitation when unsupported"],"tags":["rust","zeroclaw","rpc","approvals","elicitation","client-compat"],"backgroundTag":"rpc-request-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}