{"record":{"id":"6123c681313920a8","repo":"zeroclaw-labs/zeroclaw","slug":"discord-add-reaction-failed-status-err","errorCode":null,"errorMessage":"Discord add reaction failed ({status}): {err}","messagePattern":"Discord add reaction failed \\((.+?)\\): (.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"crates/zeroclaw-channels/src/discord/mod.rs","lineNumber":3801,"sourceCode":"            return Ok(());\n        }\n        let url = discord_reaction_url(channel_id, message_id, emoji);\n\n        let resp = self\n            .http_client()\n            .put(&url)\n            .header(\"Authorization\", format!(\"Bot {}\", self.bot_token))\n            .header(\"Content-Length\", \"0\")\n            .send()\n            .await?;\n\n        if !resp.status().is_success() {\n            let status = resp.status();\n            let err = resp\n                .text()\n                .await\n                .unwrap_or_else(|e| format!(\"<failed to read response body: {e}>\"));\n            anyhow::bail!(\"Discord add reaction failed ({status}): {err}\");\n        }\n\n        Ok(())\n    }\n\n    async fn remove_reaction(\n        &self,\n        channel_id: &str,\n        message_id: &str,\n        emoji: &str,\n    ) -> anyhow::Result<()> {\n        // Interaction sentinels are not channel ids (see add_reaction).\n        if parse_discord_interaction_target(channel_id).is_some() {\n            return Ok(());\n        }\n        let url = discord_reaction_url(channel_id, message_id, emoji);\n\n        let resp = self","sourceCodeStart":3783,"sourceCodeEnd":3819,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/discord/mod.rs#L3783-L3819","documentation":"add_reaction PUTs /channels/{channel_id}/messages/{message_id}/reactions/{emoji}/@me (URL-encoded by discord_reaction_url, skin-tone variants reduced to the base glyph). Non-2xx becomes this error with the response body. Interaction sentinel targets are filtered before the call since they are not real channels. Dominant causes: 403 50001 Missing Permissions (ADD_REACTIONS), 10014 Unknown Emoji (custom emoji from another guild or name typo), 429 rate limiting, 404 deleted message/channel.","triggerScenarios":"Bot lacks Add Reactions on the target channel; using a :name:id: custom emoji not present in that guild; unicode emoji mangled by encoding (variation selectors stripped); reacting to a message deleted between send and react; reaction bursts hitting per-channel limits.","commonSituations":"Failure-signal reactions (⚠️ from decide_failure_reactions) applied in channels where the bot only has Send Messages; emoji copied from another server; restrictive role overrides.","solutions":["Match the body: 50001 → grant Add Reactions; 10014 → use a guild-available or standard unicode emoji; 429 → back off; 10008 → message gone, skip","Prefer standard unicode glyphs for signal reactions instead of custom server emoji","Grant the bot ADD_REACTIONS wherever it posts","Treat reaction failure as best-effort: log it, never fail the send"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = channel.add_reaction(ch, msg_id, \"⚠️\").await {\n    tracing::warn!(\"signal reaction failed: {e}\"); // decoration only; never fail the send\n}","preventionTips":["Audit ADD_REACTIONS on every channel the bot posts to","Use standard unicode emoji for cross-guild portability","Never let reaction errors fail message delivery"],"tags":["discord","reactions","emoji","permissions"],"backgroundTag":"discord-reaction-errors","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}