zeroclaw-labs/zeroclaw · error · anyhow::Error
post failed ({status}): {body}
Error message
post failed ({status}): {body} What it means
A shared POST helper used by `Channel::send` (and other call paths) bails when the HTTP status is not success, including the status and the response body. For sends, the usual meanings are: 403 the bot is not in the target channel, 401 bad/expired token or session, 404 wrong channel/user ID, 400 payload rejected.
Source
Thrown at crates/zeroclaw-channels/src/mattermost.rs:740
);
}
let token = self.token().await?;
let resp = self
.http_client()
.post(format!("{}/api/v4/posts", self.base_url))
.bearer_auth(token)
.json(&body_map)
.send()
.await?;
let status = resp.status();
if !status.is_success() {
let body = resp
.text()
.await
.unwrap_or_else(|e| format!("<failed to read response: {e}>"));
bail!("post failed ({status}): {body}");
}
Ok(())
}
async fn listen(&self, tx: tokio::sync::mpsc::Sender<ChannelMessage>) -> Result<()> {
match self.listen_mode {
MattermostListenMode::Polling => self.listen_polling(tx).await,
MattermostListenMode::Websocket => self.listen_websocket(tx).await,
}
}
async fn health_check(&self) -> bool {
let Ok(token) = self.token().await else {
return false;
};
self.http_client()
.get(format!("{}/api/v4/users/me", self.base_url))View on GitHub (pinned to 88bb9c8533)
Solutions
- Read the status and body embedded in the message — Mattermost's body states the reason
- 403: add the bot to the channel via `POST /api/v4/channels/{channel_id}/members`
- 401: refresh `bot_token` or let the channel re-login
- 404: correct the channel ID or recipient (`@username` / user ID)
Defensive patterns
Strategy: try-catch
Try / catch
if let Err(e) = mm_channel.send(message).await {
let msg = e.to_string();
if msg.starts_with("post failed (403") {
// join channel then retry once
} else if msg.starts_with("post failed (401") {
// refresh token, do not retry with the same session
}
} Prevention
- Ensure the bot is a member of every channel it may reply in before routing messages there
- Parse the status code from the error body to route handling (403 join, 401 re-auth, 404 fix ID)
- Watch for archived/renamed channels when send failures cluster
When it happens
Trigger: Mattermost `send()` posting to a channel the bot has not joined, a typo'd channel or recipient ID, a token revoked since login, or content the server rejects.
Common situations: Bot removed from the channel between discovery and send; channel archived; long-lived session token expired mid-run; message exceeds server limits.
Related errors
- GET /channels/{id} returned {}: explicit channel_id is not a
- GET /users/me/channels returned {}
- login failed ({status}): {body}
- Mochat send message failed ({status}): {err}
- Talk API error: {status}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/54aa12299e7fea78.
Report an issue: GitHub.