{"record":{"id":"bb50ccb38fcad88f","repo":"zeroclaw-labs/zeroclaw","slug":"rpc-elicitation-create-timed-out-after-timeout","errorCode":null,"errorMessage":"RPC elicitation/create timed out after {timeout:?}","messagePattern":"RPC elicitation/create timed out after (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/zeroclaw-runtime/src/rpc/approval_channel.rs","lineNumber":239,"sourceCode":"    ) -> 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,\n        question: &str,\n        choices: &[String],","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/rpc/approval_channel.rs#L221-L257","documentation":"The elicitation approval path wraps the rpc.request(\"elicitation/create\", ...) future in tokio::time::timeout with a caller-supplied duration. If the operator never answers within that window, the timeout arm bails with the elapsed duration. This is an expected operational outcome — an unanswered prompt — distinct from error 878 where the RPC itself errored.","triggerScenarios":"Operator is away or misses the prompt before the timeout expires; the client renders the elicitation form but nobody interacts; timeout configured too aggressively for human response times; UI swallowed the prompt (notification lost, window hidden) so no answer ever arrives.","commonSituations":"Unattended automation hitting approval gates; timeouts tuned for fast acks applied to rare high-stakes approvals; first-time users unfamiliar with the prompt UI; long-running sessions where prompts queue behind other activity.","solutions":["Raise the elicitation/approval timeout configuration to match realistic human response time for the deployment","Verify the client actually surfaces the prompt (check notification settings, visible session)","Design callers to treat timeout as non-consent: catch this bail and take the safe default/deny path","For unattended flows, pre-configure auto-approval policies so human prompts never block"],"exampleFix":"// before: timeout treated as a hard error\nlet ans = channel.request_choice(&q, &choices, Duration::from_secs(30)).await?;\n\n// after: timeout degrades to deny\nmatch channel.request_choice(&q, &choices, Duration::from_secs(120)).await {\n    Ok(Some(c)) => c,\n    other => { tracing::warn!(\"no operator answer, denying\"); deny() }\n}","handlingStrategy":"fallback","validationCode":null,"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(\"timed out\") => {\n        // operator absent: take the safe default/deny and continue — never block the runtime\n        default_choice()\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Size approval timeouts for real human response times in that deployment (minutes, not seconds)","Verify clients visibly surface elicitation prompts before relying on them for approvals","Use auto-approval policies for unattended flows so timeouts never stall automation","Alert on frequent approval timeouts — they usually mean prompts are not reaching a human"],"tags":["rust","zeroclaw","timeout","approvals","rpc","elicitation"],"backgroundTag":"request-timeout","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}