{"record":{"id":"863ccfbcb4ed13b0","repo":"zeroclaw-labs/zeroclaw","slug":"rpc-elicitation-create-multi-timed-out-after-ti","errorCode":null,"errorMessage":"RPC elicitation/create (multi) timed out after {timeout:?}","messagePattern":"RPC elicitation/create \\(multi\\) timed out after (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/rpc/approval_channel.rs","lineNumber":278,"sourceCode":"        timeout: Duration,\n    ) -> anyhow::Result<Option<Vec<String>>> {\n        let req = ElicitationRequest {\n            session_id: self.session_id.clone(),\n            mode: ElicitationMode::Form,\n            message: question.to_string(),\n            requested_schema: multi_select_schema(choices, min_items, max_items),\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)) => anyhow::bail!(\n                \"RPC elicitation/create (multi) failed: {} ({})\",\n                e.message,\n                e.code\n            ),\n            Err(_) => {\n                anyhow::bail!(\"RPC elicitation/create (multi) timed out after {timeout:?}\")\n            }\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 texts = decode_multi_select_accept(&content, choices)?;\n                Ok(Some(texts))\n            }\n            ElicitationResponse::Decline | ElicitationResponse::Cancel => Ok(None),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::sync::Arc;","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/rpc/approval_channel.rs#L260-L296","documentation":"The multi-select elicitation call `elicitation/create` did not complete within the caller-supplied timeout (tokio::time::timeout elapsed). The connected client never answered the form and the connection did not surface an error, so the runtime gives up rather than blocking the approval flow indefinitely.","triggerScenarios":"Operator is away or the client UI never renders the request; the websocket/stdio connection stalls without closing (NAT drop, suspended laptop); the client event loop is blocked so the response is produced but never delivered; timeout set shorter than realistic human response time.","commonSituations":"Short approval timeouts (e.g. 30s) used with human-in-the-loop prompts; client on an unstable network; backgrounded TUI/mobile client that stops pumping messages; load-test clients that never answer elicitations.","solutions":["Increase the timeout passed to request_multi_choice to match the expected human response window.","Verify client connectivity (heartbeats/pings) before issuing the ask.","Ensure the client event loop is not blocked while a form is pending.","Treat timeout as 'no selection' (the single-select approval path maps timeout to Deny/TimedOut) and decide the fallback behavior explicitly."],"exampleFix":"// before\nlet picks = channel\n    .request_multi_choice(q, &choices, 1, 3, Duration::from_secs(30))\n    .await?;\n\n// after — allow a real operator window, treat timeout as no selection\nmatch channel\n    .request_multi_choice(q, &choices, 1, 3, Duration::from_secs(300))\n    .await\n{\n    Ok(Some(picks)) => { /* proceed */ }\n    Ok(None) => { /* declined/cancelled */ }\n    Err(e) if e.to_string().contains(\"timed out\") => {\n        tracing::warn!(\"elicitation timed out; continuing without selection\");\n    }\n    Err(e) => return Err(e),\n}","handlingStrategy":"retry","validationCode":"// Before asking, confirm the client recently answered a ping/heartbeat\n// and size the timeout to the human response window, not a network RTT.","typeGuard":null,"tryCatchPattern":"Err(e) if e.to_string().contains(\"(multi) timed out\") => {\n    // one retry for a stalled-but-alive connection, then treat as no-selection\n}","preventionTips":["Choose timeouts based on expected human decision time (minutes, not seconds).","Monitor client liveness (heartbeats) before issuing blocking prompts.","Decide and document the denial behavior on timeout so the workflow cannot hang."],"tags":["timeout","rpc","elicitation","approval"],"backgroundTag":"request-timeout","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}