{"record":{"id":"9dad91d264b1c16c","repo":"zeroclaw-labs/zeroclaw","slug":"acp-elicitation-create-multi-failed","errorCode":null,"errorMessage":"ACP elicitation/create (multi) failed: {} ({})","messagePattern":"ACP elicitation/create \\(multi\\) failed: (.+?) \\((.+?)\\)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/acp_channel.rs","lineNumber":388,"sourceCode":"        }\n        if !self.client_caps.form {\n            // No legacy fallback for multi-select — session/request_permission\n            // is single-select-only. Signal Ok(None) so the caller (poll tool)\n            // takes its own non-ACP fallback path.\n            return Ok(None);\n        }\n\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                \"ACP elicitation/create (multi) failed: {} ({})\",\n                e.message,\n                e.code\n            ),\n            Err(_) => {\n                anyhow::bail!(\"ACP elicitation/create (multi) timed out after {timeout:?}\")\n            }\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 =\n                    zeroclaw_api::elicitation::decode_multi_select_accept(&content, choices)?;\n                Ok(Some(texts))\n            }\n            ElicitationResponse::Decline | ElicitationResponse::Cancel => Ok(None),","sourceCodeStart":370,"sourceCodeEnd":406,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/acp_channel.rs#L370-L406","documentation":"The multi-select elicitation/create JSON-RPC call returned a protocol error (message + code). This path runs only for clients advertising elicitation.form; ZeroClaw sends a schema built by multi_select_schema(choices, min_items, max_items) and the client rejected the call itself rather than answering it. The client's code and message are embedded verbatim.","triggerScenarios":"request_multi_choice on a form-capable client where elicitation/create fails: the requestedSchema fails client validation (impossible min/max bounds, too few choices), the handler is unimplemented, or the sessionId is stale.","commonSituations":"min_items/max_items computed from dynamic data producing an invalid range; strict JSON-Schema validation on the client; session reuse after reconnect; capability advertised but not implemented.","solutions":["Read the embedded (code, message) — it is the client's exact reason for rejecting the multi-select prompt.","Validate the bounds before calling: min_items >= 1, max_items >= min_items, and choices.len() >= min_items.","Verify the session is live and the client truly implements elicitation/create for multi-select schemas.","If multi-select keeps failing, degrade to repeated single-select questions via request_choice."],"exampleFix":"// before\nlet picks = ch.request_multi_choice(q, &choices, min, max, timeout).await?;\n\n// after\nif min == 0 || max < min || choices.len() < min {\n    anyhow::bail!(\"invalid multi-select bounds: min={min} max={max} choices={}\", choices.len());\n}\nlet picks = ch.request_multi_choice(q, &choices, min, max, timeout).await?;","handlingStrategy":"try-catch","validationCode":"fn valid_multi_bounds(choices: &[String], min: usize, max: usize) -> bool {\n    !choices.is_empty() && min >= 1 && max >= min && choices.len() >= min\n}","typeGuard":null,"tryCatchPattern":"match ch.request_multi_choice(q, &choices, min, max, timeout).await {\n    Ok(Some(picks)) => { /* proceed */ }\n    Ok(None) => { /* form capability missing or user declined: poll-tool fallback */ }\n    Err(e) => {\n        tracing::warn!(error = %e, \"multi-select prompt failed; degrading to single-select\");\n        /* fall back to request_choice */\n    }\n}","preventionTips":["Derive min_items/max_items from the choices length, never hardcode them","Remember Ok(None) is ambiguous here (no capability or user declined) — do not treat it as a selection","Log the client's code/message verbatim for integration debugging"],"tags":["rust","acp","elicitation","jsonrpc","multi-select"],"backgroundTag":"jsonrpc-error-response","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}