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
- Add channel_ids = ["<channel snowflake>"] to the Discord channel config so empty-recipient messages have a fallback
- Set message.recipient to a concrete channel id when constructing the outgoing message
- If the empty-recipient send is intentional nowhere-land, suppress it upstream instead of relying on this error
- 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
- Always configure channel_ids as the default route on every Discord alias
- Build alert messages with an explicit recipient whenever a target is known
- Fail config validation at startup when a Discord alias has neither channel_ids nor a recipient source
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
- interaction reply target unknown or expired (id {interaction
- approval route '{route}' is not 'channel:recipient' (e.g. 'd
- approval route channel '{channel_key}' is not a configured c
- approval route channel '{channel_key}' does not support outb
- channels.discord.{alias}.bot_token is unset but the channel
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/0d244743b985ed44.
Report an issue: GitHub.