{"record":{"id":"a23e9714576835e5","repo":"zeroclaw-labs/zeroclaw","slug":"telegram-sendmessage-approval-failed-after-fallb","errorCode":null,"errorMessage":"Telegram sendMessage (approval) failed after fallback","messagePattern":"Telegram sendMessage \\(approval\\) failed after fallback","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/telegram.rs","lineNumber":4699,"sourceCode":"                        let err = r.text().await.unwrap_or_default();\n                        self.pending_approvals.lock().await.remove(&approval_id);\n                        anyhow::bail!(\"Telegram sendMessage (approval) failed ({status}): {err}\");\n                    }\n                    Err(e) => {\n                        self.pending_approvals.lock().await.remove(&approval_id);\n                        return Err(e.into());\n                    }\n                }\n            }\n            Err(e) => {\n                self.pending_approvals.lock().await.remove(&approval_id);\n                return Err(e.into());\n            }\n        };\n\n        if !send_ok {\n            self.pending_approvals.lock().await.remove(&approval_id);\n            anyhow::bail!(\"Telegram sendMessage (approval) failed after fallback\");\n        }\n\n        // Wait for the user to tap a button. Timeout is configurable via\n        // `channels.telegram.approval_timeout_secs` (default 120s).\n        let result =\n            match tokio::time::timeout(Duration::from_secs(self.approval_timeout_secs), rx).await {\n                Ok(Ok(response)) => Some(\n                    zeroclaw_api::channel::AttributedApprovalResponse::operator(response),\n                ),\n                Ok(Err(_)) => {\n                    // Sender dropped — clean up and deny. Nobody tapped.\n                    self.pending_approvals.lock().await.remove(&approval_id);\n                    Some(\n                        zeroclaw_api::channel::AttributedApprovalResponse::from_runtime(\n                            ChannelApprovalResponse::Deny,\n                            zeroclaw_api::channel::ApprovalSource::Unreachable,\n                        ),\n                    )","sourceCodeStart":4681,"sourceCodeEnd":4717,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/telegram.rs#L4681-L4717","documentation":"Defensive backstop at the end of the Telegram approval send flow: it fires when the send_ok flag is still false after the HTML sendMessage and the plain-text fallback both failed. In the current code every failure branch above either bails with the more specific 'Telegram sendMessage (approval) failed ({status}): {err}' message (error 280) or returns the reqwest transport error directly, so this branch is effectively unreachable — every path that sets nothing returns true. Seeing this message alone means the failure fell through the specific branches without capturing a status.","triggerScenarios":"Both the HTML-formatted and plain-text sendMessage attempts for an approval prompt fail without a transport error, and neither specific bail branch fires. Practically unreachable today: the fallback's non-success branch bails with the detailed error 280 first, and transport errors return early.","commonSituations":"Same conditions as error 280 (bad token, unknown chat, rate limit) persisting across both attempts; or a future refactor that breaks the match chain so failures fall through with send_ok false.","solutions":["Treat it exactly like error 280: check bot token validity, chat_id, and rate limits","Grep the logs for the preceding WARN 'Telegram sendMessage (approval) with HTML failed' — it carries the actual status and body of the first attempt","If you hit this exact message with no preceding specific error, report it as a control-flow bug in the approval send path in crates/zeroclaw-channels/src/telegram.rs"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Same handling as the specific sendMessage failure: catch, inspect,\n// and deny the pending tool call so the agent does not hang.\nif let Err(e) = approval_request.await {\n    tracing::warn!(\"approval delivery failed: {e}; defaulting to deny\");\n    return ChannelApprovalResponse::Deny;\n}","preventionTips":["Treat any approval-delivery error as 'deny by default' so tools never wait forever","Keep bot token and chat_id validated at startup (see error 280)","If this exact message appears without a preceding specific error, file a bug — the branch should be unreachable"],"tags":["telegram","bot-api","approval","unreachable-branch"],"backgroundTag":"telegram-bot-api-error","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}