{"record":{"id":"c9c58e122a786f73","repo":"zeroclaw-labs/zeroclaw","slug":"lark-add-reaction-failed-for-message-id-status","errorCode":null,"errorMessage":"Lark add_reaction failed for {message_id}: status={status}, body={err_body}","messagePattern":"Lark add_reaction failed for (.+?): status=(.+?), body=(.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"crates/zeroclaw-channels/src/lark.rs","lineNumber":2702,"sourceCode":"        let mut token = self.get_tenant_access_token().await?;\n\n        let mut retried = false;\n        loop {\n            let response = self\n                .post_message_reaction_with_token(message_id, &token, emoji_type)\n                .await?;\n\n            if response.status().as_u16() == 401 && !retried {\n                self.invalidate_token().await;\n                token = self.get_tenant_access_token().await?;\n                retried = true;\n                continue;\n            }\n\n            if !response.status().is_success() {\n                let status = response.status();\n                let err_body = response.text().await.unwrap_or_default();\n                anyhow::bail!(\n                    \"Lark add_reaction failed for {message_id}: status={status}, body={err_body}\"\n                );\n            }\n\n            let payload: serde_json::Value = response.json().await?;\n            let code = payload.get(\"code\").and_then(|v| v.as_i64()).unwrap_or(-1);\n            if code != 0 {\n                let msg = payload\n                    .get(\"msg\")\n                    .and_then(|v| v.as_str())\n                    .unwrap_or(\"unknown error\");\n                ::zeroclaw_log::record!(\n                    WARN,\n                    ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)\n                        .with_outcome(::zeroclaw_log::EventOutcome::Unknown)\n                        .with_attrs(::serde_json::json!({\n                            \"code\": code,\n                            \"message_id\": message_id,","sourceCodeStart":2684,"sourceCodeEnd":2720,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/lark.rs#L2684-L2720","documentation":"Adding an emoji reaction (POST /im/v1/messages/{message_id}/reactions) returned non-2xx. The message includes the message_id, status, and the raw body text, mapping directly to Lark's error catalog. Reactions are cosmetic acknowledgments, so callers usually treat this as non-fatal; the code!=0 variant (200 with business code) is checked separately right after this branch.","triggerScenarios":"404 for a message too old, deleted, or in a chat the bot left; 403 when the app lacks the add-reaction scope; 400 for an emoji_type not in Lark's allowed emoji key set; 429 from reaction bursts.","commonSituations":"Bot removed from the group before the reaction fires, permission changes dropping the reaction scope, or an emoji_type value that Lark does not recognize (custom vs standard emoji keys).","solutions":["Read body= in the message and map the Lark code: permission -> grant the reaction scope and republish; invalid emoji -> use a standard emoji_type key.","If the bot was removed from the chat, skip reacting for that chat.","Treat as best-effort: log and continue rather than failing the message pipeline.","Rate-limit reaction calls if 429."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_add_reaction_failure(err: &anyhow::Error) -> bool {\n    err.to_string().contains(\"Lark add_reaction failed\")\n}","tryCatchPattern":"if let Err(e) = lark.add_reaction(&message_id, emoji).await {\n    if is_add_reaction_failure(&e) {\n        tracing::debug!(error = %e, \"reaction skipped (cosmetic)\"); // never fail the turn\n    } else {\n        return Err(e);\n    }\n}","preventionTips":["Treat reactions as best-effort with debug-level logging.","Pin emoji_type values to Lark's standard emoji key list.","Rate-limit reaction calls to avoid 429 bursts."],"tags":["lark","add-reaction","http","non-fatal","emoji"],"backgroundTag":"http-error-response","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}