zeroclaw-labs/zeroclaw · warning · anyhow::Error
Signal poll requires at least 2 options (got {}); render as
Error message
Signal poll requires at least 2 options (got {}); render as text instead What it means
Raised by SignalChannel::send_poll when options.len() < 2 — a deliberate validation guard before build_poll_params and the sendPollCreate RPC. The message itself tells the caller what to do: 'render as text instead'. It fires from send_choice when the model/agent produced fewer than two options, since a one-option (or zero-option) poll is meaningless on Signal. It is a control-flow signal, not an infrastructure fault.
Source
Thrown at crates/zeroclaw-channels/src/signal.rs:544
/// Sent via signal-cli daemon's JSON-RPC `sendPollCreate` method. The
/// poll renders as native UI in modern Signal clients and emits a
/// poll-vote event (`pollAnswer` or `pollVote`, depending on signal-cli
/// version) back through the SSE stream when the user votes — see
/// `process_envelope` for how that flows back to consumers, normally as
/// a synthetic `[choice-index]N` `ChannelMessage`.
///
/// `multiple_choice = false` → single-select poll (the common case
/// for "pick one of N" agent prompts). Pass `true` to allow
/// multi-select.
pub async fn send_poll(
&self,
recipient: &str,
question: &str,
options: &[String],
multiple_choice: bool,
) -> anyhow::Result<()> {
if options.len() < 2 {
anyhow::bail!(
"Signal poll requires at least 2 options (got {}); render as text instead",
options.len()
);
}
let params = self.build_poll_params(recipient, question, options, multiple_choice);
self.rpc_request("sendPollCreate", params).await?;
Ok(())
}
}
impl ::zeroclaw_api::attribution::Attributable for SignalChannel {
fn role(&self) -> ::zeroclaw_api::attribution::Role {
::zeroclaw_api::attribution::Role::Channel(::zeroclaw_api::attribution::ChannelKind::Signal)
}
fn alias(&self) -> &str {
&self.alias
}
}View on GitHub (pinned to 88bb9c8533)
Solutions
- Catch this error in send_choice and fall back to a plain text message rendering the question and the available options
- Validate options.len() >= 2 before calling send_poll and branch to text rendering yourself
- Fix the upstream choice generation so it always yields at least two options
Example fix
// before
self.send_poll(recipient, question, options, multiple_choice).await?;
// after
if options.len() >= 2 {
self.send_poll(recipient, question, options, multiple_choice).await
} else {
let text = format!("{question}\n{}", options.join("\n"));
self.send(recipient, &text).await
} Defensive patterns
Strategy: validation
Validate before calling
fn render_choice(channel: &SignalChannel, recipient: &str, question: &str, options: &[String], multi: bool) -> BoxFuture<'_, anyhow::Result<()>> {
async move {
if options.len() >= 2 {
channel.send_poll(recipient, question, options, multi).await
} else {
let text = format!("{question}\n{}", options.join("\n"));
channel.send(recipient, &text).await
}
}
.boxed()
} Type guard
fn poll_options_valid(options: &[String]) -> bool {
options.len() >= 2 && options.iter().all(|o| !o.trim().is_empty())
} Try / catch
if let Err(err) = channel.send_poll(recipient, question, options, multi).await {
if format!("{err:#}").starts_with("Signal poll requires at least 2 options") {
let text = format!("{question}\n{}", options.join("\n"));
return channel.send(recipient, &text).await; // fallback to plain text
}
return Err(err);
} Prevention
- Validate options.len() >= 2 before every send_poll and branch to text rendering
- Fix choice-generation prompts/templates so they never emit fewer than two options
- Treat this error as a signal to fall back, never as a failure to surface to the user
When it happens
Trigger: send_choice calls send_poll with an options slice containing 0 or 1 entries — e.g. an LLM produced a single choice, a choice list was truncated, or options were parsed out of malformed output.
Common situations: Agent-generated choice prompts collapsing to one option; empty options after filtering/escaping; upstream prompt templates that allow a single-item list.
Related errors
- modal custom_id exceeds Discord's 100-char limit; cannot ope
- slash command registration failed for '{name}' ({status}): {
- unknown git channel provider `{other}` (supported: github, g
- git channel `events` routing table ignores every event type;
- invalid forge HTTP method `{}` (expected GET/POST/PATCH/PUT/
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/bd551529bca93f61.
Report an issue: GitHub.