zeroclaw-labs/zeroclaw · error
WhatsApp interactive list section '{}' capped at 10 rows (go
Error message
WhatsApp interactive list section '{}' capped at 10 rows (got {}) What it means
Each section of a WhatsApp interactive list may hold at most 10 rows; `send_interactive_list` validates every section up front and names the first offending section's title and row count. This mirrors Meta's list-message contract and fails before any HTTP call. The total message cap is 100 rows (10 sections x 10 rows).
Source
Thrown at crates/zeroclaw-channels/src/whatsapp.rs:622
pub async fn send_interactive_list(
&self,
recipient: &str,
body_text: &str,
button_text: &str,
sections: &[InteractiveListSection],
) -> anyhow::Result<()> {
if sections.is_empty() {
anyhow::bail!("WhatsApp interactive list requires at least one section");
}
if sections.len() > 10 {
anyhow::bail!(
"WhatsApp interactive list capped at 10 sections (got {})",
sections.len()
);
}
for s in sections {
if s.rows.len() > 10 {
anyhow::bail!(
"WhatsApp interactive list section '{}' capped at 10 rows (got {})",
s.title,
s.rows.len()
);
}
}
let url = format!(
"https://graph.facebook.com/v18.0/{}/messages",
self.endpoint_id
);
ensure_https(&url)?;
let to = recipient.strip_prefix('+').unwrap_or(recipient);
let action_sections: Vec<serde_json::Value> = sections
.iter()
.map(|s| {
let rows: Vec<serde_json::Value> = s
.rows
.iter()View on GitHub (pinned to 88bb9c8533)
Solutions
- Chunk rows into sections of at most 10 (`options.chunks(10)`), the same way `send_choice` does.
- Trim the list or paginate interactively (e.g. a final 'More' row that triggers the next page).
- For flat option lists, prefer `send_choice`, which chunks automatically.
Example fix
// before
let sections = vec![InteractiveListSection {
title: "All".into(),
rows: all_25_rows, // > 10 rows -> bails
}];
// after
let sections: Vec<_> = all_rows
.chunks(10)
.enumerate()
.map(|(i, c)| InteractiveListSection {
title: format!("Options {}-{}", i * 10 + 1, i * 10 + c.len()),
rows: c.to_vec(),
})
.collect(); Defensive patterns
Strategy: validation
Validate before calling
for s in §ions {
anyhow::ensure!(s.rows.len() <= 10, "section '{}' has {} rows (max 10)", s.title, s.rows.len());
}
channel.send_interactive_list(recipient, body, button_text, §ions).await Type guard
fn rows_within_cap(section: &InteractiveListSection) -> bool {
section.rows.len() <= 10
} Prevention
- Always build sections with `chunks(10)` rather than pushing rows into one accumulator section.
- Add a unit test asserting every generated section has 1..=10 rows.
- Watch pagination code: a 'last page' section built from a remainder slice still must respect the cap.
When it happens
Trigger: Passing any `InteractiveListSection` whose `rows.len() > 10` — e.g. a single 'All items' section containing 25 rows, or uneven chunking that leaves a long tail in one section.
Common situations: Flat item lists dumped into one section; forgetting that the per-section cap (10) is far smaller than the total cap (100); manual section construction that bypasses the chunking `send_choice` does.
Related errors
- WhatsApp interactive list capped at 10 sections (got {})
- WhatsApp send_choice: {} options exceeds list cap ({}); spli
- WhatsApp interactive list requires at least one section
- WhatsApp interactive buttons require 1..=3 options (got {});
- WhatsApp location marker must be `lat,lng[,name[,address]]`
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/9f79bdb1b9fa8ee2.
Report an issue: GitHub.