zeroclaw-labs/zeroclaw · error · anyhow::Error

discord send has no recipient: message.recipient is empty an

Error message

discord send has no recipient: message.recipient is empty and no channel_ids are configured to fall back to

What it means

send() resolves the delivery target via effective_discord_recipient: a non-empty message.recipient wins; empty falls back to the first configured channel_ids entry. When recipient is empty AND channel_ids is empty, there is nowhere to POST (the code would hit /channels//messages), so it logs a WARN and bails. Typical producer: system-generated messages such as escalation alerts that carry no per-message target on a channel never given default channel_ids.

Source

Thrown at crates/zeroclaw-channels/src/discord/mod.rs:1794

            if self.stream_mode == zeroclaw_config::schema::StreamMode::MultiMessage {
                self.multi_message_delay_ms
            } else {
                500
            };

        let mut first_message_id: Option<String> = None;
        let effective_recipient =
            match effective_discord_recipient(&message.recipient, &self.channel_ids) {
                Some(r) => r,
                None => {
                    ::zeroclaw_log::record!(
                        WARN,
                        ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)
                            .with_outcome(::zeroclaw_log::EventOutcome::Unknown),
                        "discord send has no recipient: message.recipient is empty and no \
                     channel_ids are configured to fall back to"
                    );
                    anyhow::bail!(
                        "discord send has no recipient: message.recipient is empty and no \
                     channel_ids are configured to fall back to"
                    );
                }
            };
        for (i, chunk) in chunks.iter().enumerate() {
            let message_id = if i == 0 && (!embeds.is_empty() || !component_action_rows.is_empty())
            {
                let payload = DiscordOutgoing {
                    content: Some(chunk.clone()),
                    embeds: embeds.clone(),
                    components: component_action_rows.clone(),
                    ..Default::default()
                };
                if local_files.is_empty() {
                    send_discord_message_payload(
                        &client,
                        &self.bot_token,

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Add channel_ids = ["<channel snowflake>"] to the Discord channel config so empty-recipient messages have a fallback
  2. Set message.recipient to a concrete channel id when constructing the outgoing message
  3. If the empty-recipient send is intentional nowhere-land, suppress it upstream instead of relying on this error
  4. Verify the right alias — check the per-alias channel config the message actually routed to

Example fix

# before
[channels.discord.default]
bot_token = "..."

# after — escalation alerts with empty recipients fall back to this channel
[channels.discord.default]
bot_token = "..."
channel_ids = ["1234567890123456789"]
Defensive patterns

Strategy: validation

Validate before calling

// Mirror of effective_discord_recipient before calling send:
let target = if msg.recipient.is_empty() {
    channel_ids.first().map(String::as_str)
} else {
    Some(msg.recipient.as_str())
};
if target.is_none() {
    // nowhere to deliver — fix config or the message instead of sending
}

Prevention

When it happens

Trigger: Escalation/alert SendMessage built with an empty recipient on a Discord channel configured only with a bot token; channel_ids lost in a config migration or split into per-alias configs; message routed to an alias whose channel has no channel_ids; gateway-driven sends relying on the fallback that was never configured.

Common situations: Enabling alerting before the bot was invited anywhere; splitting one Discord config into multiple aliases and forgetting channel_ids on the new one; tests constructing SendMessage with default values.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/0d244743b985ed44. Report an issue: GitHub.