{"record":{"id":"160045afb81e0473","repo":"zeroclaw-labs/zeroclaw","slug":"whatsapp-interactive-list-requires-at-least-one-se","errorCode":null,"errorMessage":"WhatsApp interactive list requires at least one section","messagePattern":"WhatsApp interactive list requires at least one section","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/whatsapp.rs","lineNumber":612,"sourceCode":"        self.post_to_meta(&url, &body).await\n    }\n\n    /// Send an interactive list message (more than 3 options, up to 10\n    /// rows per section, up to 10 sections per Meta's limits). `sections`\n    /// each carry a section title + rows. Each row's `id` round-trips\n    /// through the inbound `interactive.list_reply.id` as `[choice]<id>`.\n    ///\n    /// `button_text` is the button label that opens the list (Meta limits\n    /// to 20 chars).\n    pub async fn send_interactive_list(\n        &self,\n        recipient: &str,\n        body_text: &str,\n        button_text: &str,\n        sections: &[InteractiveListSection],\n    ) -> anyhow::Result<()> {\n        if sections.is_empty() {\n            anyhow::bail!(\"WhatsApp interactive list requires at least one section\");\n        }\n        if sections.len() > 10 {\n            anyhow::bail!(\n                \"WhatsApp interactive list capped at 10 sections (got {})\",\n                sections.len()\n            );\n        }\n        for s in sections {\n            if s.rows.len() > 10 {\n                anyhow::bail!(\n                    \"WhatsApp interactive list section '{}' capped at 10 rows (got {})\",\n                    s.title,\n                    s.rows.len()\n                );\n            }\n        }\n        let url = format!(\n            \"https://graph.facebook.com/v18.0/{}/messages\",","sourceCodeStart":594,"sourceCodeEnd":630,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/whatsapp.rs#L594-L630","documentation":"`send_interactive_list` builds a WhatsApp interactive list message, and Meta's contract requires at least one section. The channel bails immediately when the `sections` slice is empty rather than sending a request that would fail server-side. This is a local precondition failure; no network call is made.","triggerScenarios":"Calling `send_interactive_list(recipient, body_text, button_text, &[])` — typically sections produced by a `chunks`/`map`/filter chain over an empty or fully filtered-out option collection.","commonSituations":"Grouping options into sections algorithmically (e.g. `options.chunks(10)`) when `options` itself is empty; an upstream data source returning zero rows; scaffolding code passing a placeholder empty vec.","solutions":["Guard the empty case upstream: with no options, send the prompt as plain text via `send` (or no-op when the prompt is also empty).","Debug why the sections-producing collection was empty — usually the input list was empty or fully filtered.","Prefer `send_choice`, which already handles empty options by falling back to a plain-text send."],"exampleFix":"// before\nchannel\n    .send_interactive_list(to, \"Choose:\", \"Choose\", &sections)\n    .await?; // sections is empty -> bails\n\n// after\nif sections.is_empty() {\n    channel.send(&SendMessage::new(prompt, to)).await?;\n} else {\n    channel.send_interactive_list(to, \"Choose:\", \"Choose\", &sections).await?;\n}","handlingStrategy":"validation","validationCode":"if sections.is_empty() {\n    anyhow::bail!(\"refusing to send an empty interactive list; check the option source\");\n}\nchannel.send_interactive_list(recipient, body, button_text, &sections).await","typeGuard":"fn has_list_sections(sections: &[InteractiveListSection]) -> bool {\n    !sections.is_empty()\n}","tryCatchPattern":null,"preventionTips":["Prefer `send_choice` for caller-supplied option lists; its empty-options path already degrades to plain text.","Assert non-empty inputs where sections are generated (empty collection in, bail early with context).","Property-test section builders so they never emit zero sections for non-empty input."],"tags":["whatsapp","interactive-list","validation","rust"],"backgroundTag":"argument-validation-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}