zeroclaw-labs/zeroclaw · error
Telegram sendVoice failed: {err}
Error message
Telegram sendVoice failed: {err} What it means
sendVoice() uploads a multipart sendVoice request and bails with Telegram's response body on non-2xx. Telegram only accepts voice notes as OGG encoded with Opus, so this error fires when that contract or the chat itself is broken.
Source
Thrown at crates/zeroclaw-channels/src/telegram.rs:3462
if let Some(tid) = thread_id {
form = form.text("message_thread_id", tid.to_string());
}
if let Some(cap) = caption {
form = form.text("caption", cap.to_string());
}
let resp = self
.http_client()
.post(self.api_url("sendVoice"))
.multipart(form)
.send()
.await?;
if !resp.status().is_success() {
let err = resp.text().await?;
anyhow::bail!("Telegram sendVoice failed: {err}");
}
::zeroclaw_log::record!(
INFO,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)
.with_attrs(::serde_json::json!({"chat_id": chat_id, "file_name": file_name})),
"voice sent to"
);
Ok(())
}
/// Send a file by URL (Telegram will download it)
pub async fn send_document_by_url(
&self,
chat_id: &str,
thread_id: Option<&str>,
url: &str,
caption: Option<&str>,View on GitHub (pinned to 88bb9c8533)
Solutions
- Read the embedded `description` for the exact reason.
- Verify the file is OGG/Opus: `ffprobe file.ogg` should report codec=opus; re-encode with `ffmpeg -i in.wav -c:a libopus out.ogg`.
- Confirm chat_id/thread_id are valid and the bot is not blocked.
- On 429, honor retry_after and resend once.
Defensive patterns
Strategy: validation
Validate before calling
// confirm the payload is OGG/Opus before uploading let head = tokio::fs::read(&path).await?; anyhow::ensure!(head.starts_with(b"OggS"), "voice file is not an OGG container");
Type guard
fn is_ogg_opus(path: &Path) -> bool {
// cheap header check; ffprobe -c:a opus is authoritative
std::fs::read(path).map(|b| b.starts_with(b"OggS")).unwrap_or(false)
} Try / catch
if let Err(e) = channel.send_voice(chat, thread, path, None).await {
if e.to_string().contains("wrong type of the current file") {
let fixed = transcode_to_opus(path).await?; // ffmpeg -c:a libopus
return channel.send_voice(chat, thread, &fixed, None).await;
}
return Err(e);
} Prevention
- Always produce voice notes with `ffmpeg -c:a libopus` into .ogg; never rely on default codecs.
- Add a pipeline test that fails when TTS output is not OggS+Opus.
- Keep chat_id/thread_id valid and honor 429 retry_after.
When it happens
Trigger: 400 'wrong type of the current file' when the upload is OGG/Vorbis, WAV, or MP3 instead of OGG/Opus; 400 chat not found / invalid thread_id; 403 blocked/kicked; 429 flood control; oversized voice buffers.
Common situations: TTS pipeline skipping the ffmpeg Opus transcode after a config change; ffmpeg writing default vorbis codec; speech clips converted with the wrong flags; rate limits during rapid conversational replies.
Related errors
- {method} failed: status={status}, body={body}
- Telegram sendDocument failed: {err}
- Telegram sendPhoto failed: {err}
- Telegram sendVideo failed: {err}
- Telegram sendAudio failed: {err}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/d165ca5a41c27675.
Report an issue: GitHub.