{"record":{"id":"5d7e8a54c29d452c","repo":"zeroclaw-labs/zeroclaw","slug":"method-by-url-failed-err","errorCode":null,"errorMessage":"{method} by URL failed: {err}","messagePattern":"(.+?) by URL failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/telegram.rs","lineNumber":3037,"sourceCode":"\n        if let Some(tid) = thread_id {\n            body[\"message_thread_id\"] = serde_json::Value::String(tid.to_string());\n        }\n\n        if let Some(cap) = caption {\n            body[\"caption\"] = serde_json::Value::String(cap.to_string());\n        }\n\n        let resp = self\n            .http_client()\n            .post(self.api_url(method))\n            .json(&body)\n            .send()\n            .await?;\n\n        if !resp.status().is_success() {\n            let err = resp.text().await?;\n            anyhow::bail!(\"{method} by URL failed: {err}\");\n        }\n\n        ::zeroclaw_log::record!(\n            INFO,\n            ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note).with_attrs(\n                ::serde_json::json!({\"method\": method, \"chat_id\": chat_id, \"url\": url})\n            ),\n            \"sent to\"\n        );\n        Ok(())\n    }\n\n    async fn send_attachment(\n        &self,\n        chat_id: &str,\n        thread_id: Option<&str>,\n        attachment: &TelegramAttachment,\n    ) -> anyhow::Result<()> {","sourceCodeStart":3019,"sourceCodeEnd":3055,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/telegram.rs#L3019-L3055","documentation":"The send-media-by-URL path posts a JSON body (method such as sendPhoto/sendDocument with a URL instead of an upload) and bails with Telegram's response body on non-2xx. Telegram's servers fetch the URL themselves, so rejections usually point at the URL or its content rather than the chat.","triggerScenarios":"400 'failed to get HTTP URL content' when Telegram cannot fetch the URL (host unreachable from Telegram's network, wrong MIME type, redirect to an HTML page); malformed URL; 403 chat not found/blocked; content behind the URL exceeding the type's size limits.","commonSituations":"Links to localhost/intranet hosts Telegram cannot reach; expired signed URLs or hotlink protection; sending a web page URL where a direct file URL is required; content-type sniffing failing on unusual extensions.","solutions":["Fetch the URL yourself from a public network (curl with the same headers) — Telegram must be able to download it.","Use the direct file URL with a Content-Type matching the method (image/jpeg for sendPhoto, etc.), not an HTML page.","If the host is private, download the file locally and use the multipart path (send_photo/send_document) instead of the URL variant.","Read the embedded `description` in the error body for the exact Bot API reason."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// prove the URL is publicly fetchable and the right content type before sending\nlet resp = reqwest::Client::new().head(url).send().await?;\nanyhow::ensure!(resp.status().is_success(), \"URL not fetchable: {}\", resp.status());\nanyhow::ensure!(resp.headers().get(CONTENT_TYPE).map_or(false, |v| v.to_str().unwrap_or(\"\").starts_with(\"image/\")), \"URL is not an image\");","typeGuard":"fn is_url_fetch_failure(err: &anyhow::Error) -> bool {\n    err.to_string().contains(\"failed to get HTTP URL content\")\n}","tryCatchPattern":"if let Err(e) = channel.send_media_by_url(chat, url).await {\n    if is_url_fetch_failure(&e) {\n        // mirror the channel's own fallback: send the link as plain text\n        return channel.send_text_chunks(&format!(\"{label}: {url}\"), chat, thread).await;\n    }\n    return Err(e);\n}","preventionTips":["Never pass intranet/localhost URLs; download the file and use the multipart senders instead.","Pre-check the URL returns the expected Content-Type with a HEAD request.","Keep a text-link fallback for every URL send, as send_attachment already does."],"tags":["telegram","send-by-url","media","bot-api"],"backgroundTag":"telegram-send-by-url-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}