{"record":{"id":"dce07e170df4041a","repo":"zeroclaw-labs/zeroclaw","slug":"audio-download-failed-after-token-refresh","errorCode":null,"errorMessage":"audio download failed after token refresh: {}","messagePattern":"audio download failed after token refresh: (.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"crates/zeroclaw-channels/src/lark.rs","lineNumber":1952,"sourceCode":"            .await?;\n\n        let status = resp.status();\n        if !status.is_success() {\n            let body_text = resp.text().await.unwrap_or_default();\n            let body: serde_json::Value =\n                serde_json::from_str(&body_text).unwrap_or_else(|_| serde_json::json!({}));\n\n            if should_refresh_lark_tenant_token(status, &body) {\n                self.invalidate_token().await;\n                let token = self.get_tenant_access_token().await?;\n                let resp = self\n                    .http_client()\n                    .get(&url)\n                    .header(\"Authorization\", format!(\"Bearer {token}\"))\n                    .send()\n                    .await?;\n                if !resp.status().is_success() {\n                    anyhow::bail!(\n                        \"audio download failed after token refresh: {}\",\n                        resp.status()\n                    );\n                }\n                let bytes = Self::stream_audio_bytes(resp).await?;\n                return Ok((bytes, inferred_audio_filename(file_key)));\n            }\n\n            anyhow::bail!(\"audio download failed: {}\", status);\n        }\n        let bytes = Self::stream_audio_bytes(resp).await?;\n        Ok((bytes, inferred_audio_filename(file_key)))\n    }\n\n    async fn try_transcribe_audio_message(\n        &self,\n        message_id: &str,\n        content: &str,","sourceCodeStart":1934,"sourceCodeEnd":1970,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/lark.rs#L1934-L1970","documentation":"While downloading a Lark audio resource, the first attempt signaled an auth problem (401 or code 99991663); the channel invalidated its token, fetched a fresh one, and retried — and the retried download still returned non-2xx. Since the fresh token did not help, the resource itself is usually the problem (expired, deleted, or access-restricted) rather than authentication. Only the retry status is reported.","triggerScenarios":"Lark message resources that have expired out of retention, a message deleted by the user before processing, a file with restricted access the bot cannot read, or 404 on an invalid file_key.","commonSituations":"Queue backlogs mean audio messages are processed long after arrival, past resource retention; users delete messages immediately after sending; retention policy on the tenant shortens resource availability.","solutions":["Reduce processing latency so audio is fetched promptly after the webhook event.","Branch on status: 404 -> resource expired, skip gracefully; 403 -> check message-resource read permission on the app.","Confirm the app has the message-resource (im resource) read scope granted and published."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":"fn is_lark_audio_download_error(err: &anyhow::Error) -> bool {\n    err.to_string().contains(\"audio download failed\")\n}","tryCatchPattern":"match lark.transcribe_audio(msg).await {\n    Ok(text) => use_text(text),\n    Err(e) if is_lark_audio_download_error(&e) => {\n        // expired/deleted resource with a fresh token: reply without transcription\n        continue_without_transcription(msg).await;\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Process audio-bearing webhooks first; resource retention is finite.","Make transcription a best-effort stage with its own error boundary.","Grant and publish the message-resource read scope up front."],"tags":["lark","audio","token-refresh","expired-resource","download"],"backgroundTag":"expired-resource-url","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}