zeroclaw-labs/zeroclaw · error · anyhow::Error
Talk API error: {status}
Error message
Talk API error: {status} What it means
`send_to_room` posts an HMAC-signed message to the Talk bot API and bails with `Talk API error: {status}` on any non-success response; the status and body are also logged at ERROR level with the module's structured logger. Common statuses: 401 bad/mismatched bot secret, 404 unknown room token, 400 rejected message.
Source
Thrown at crates/zeroclaw-channels/src/nextcloud_talk.rs:549
}
async fn send_to_room(&self, room_token: &str, content: &str) -> anyhow::Result<()> {
let response = self.post_to_room(room_token, content).await?;
if response.status().is_success() {
return Ok(());
}
let status = response.status();
let body = response.text().await.unwrap_or_default();
::zeroclaw_log::record!(
ERROR,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)
.with_outcome(::zeroclaw_log::EventOutcome::Failure)
.with_attrs(::serde_json::json!({"status": status.to_string(), "body": body})),
"Talk send failed:"
);
anyhow::bail!("Talk API error: {status}");
}
/// Send a message and return the response from Nextcloud Talk.
async fn send_to_room_with_id(
&self,
room_token: &str,
content: &str,
) -> anyhow::Result<String> {
let response = self.post_to_room(room_token, content).await?;
if !response.status().is_success() {
let status = response.status();
let body = response.text().await.unwrap_or_default();
::zeroclaw_log::record!(
WARN,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)
.with_outcome(::zeroclaw_log::EventOutcome::Unknown)
.with_attrs(::serde_json::json!({"status": status.to_string(), "body": body})),View on GitHub (pinned to 88bb9c8533)
Solutions
- Check the structured log entry — it includes the status and the response body, which states the reason
- 401: re-copy the current bot secret into `bot_token`
- 404: verify the room token matches the conversation the bot is in
- Ensure the bot is still a participant of the target room
Defensive patterns
Strategy: try-catch
Try / catch
match talk_channel.send(msg).await {
Err(e) if e.to_string().starts_with("Talk API error: 401") => {
// secret mismatch: re-copy bot secret, then retry once
}
Err(e) if e.to_string().starts_with("Talk API error: 404") => {
// wrong room token: fix mapping, do not retry
}
other => other,
} Prevention
- Match on the status in the error string to choose re-auth vs fix-room vs retry
- Check the structured log for the response body — it has the server's reason
- When the bot secret is rotated in Nextcloud, update config in the same change
When it happens
Trigger: `Channel::send` (or `finalize_draft`) posting to a room where signing fails validation (stale secret), the bot was removed from the conversation, or the room token is wrong.
Common situations: Bot secret regenerated in Nextcloud after config was written; bot kicked from the conversation; room token copied from a share link instead of the API token; message over Talk's length limit after truncation rules.
Related errors
- post failed ({status}): {body}
- Mochat send message failed ({status}): {err}
- Gmail OAuth token is not configured for sending
- send failed {context}: status={status}, body={body}
- GET /channels/{id} returned {}: explicit channel_id is not a
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/78a719a026a0be26.
Report an issue: GitHub.