zeroclaw-labs/zeroclaw · error · anyhow::Error
Mochat send message failed ({status}): {err}
Error message
Mochat send message failed ({status}): {err} What it means
`MochatChannel::send` POSTs to `<api_url>/api/message/send` with a Bearer token and bails when the HTTP status is not success, echoing the status and body. This is a transport/auth-level failure (401 bad api_token, 404 wrong api_url, 5xx gateway/server down), distinct from the in-body business `code` error raised after this check.
Source
Thrown at crates/zeroclaw-channels/src/mochat.rs:121
"toUserId": message.recipient,
"msgType": "text",
"content": {
"text": message.content,
}
});
let resp = self
.http_client()
.post(format!("{}/api/message/send", self.api_url))
.header("Authorization", format!("Bearer {}", self.api_token))
.json(&body)
.send()
.await?;
if !resp.status().is_success() {
let status = resp.status();
let err = resp.text().await.unwrap_or_default();
anyhow::bail!("Mochat send message failed ({status}): {err}");
}
let result: serde_json::Value = resp.json().await?;
let code = result.get("code").and_then(|v| v.as_i64()).unwrap_or(-1);
if code != 0 && code != 200 {
let msg = result
.get("msg")
.or_else(|| result.get("message"))
.and_then(|v| v.as_str())
.unwrap_or("unknown error");
anyhow::bail!("Mochat API error (code={code}): {msg}");
}
Ok(())
}
async fn listen(&self, tx: tokio::sync::mpsc::Sender<ChannelMessage>) -> anyhow::Result<()> {
::zeroclaw_log::record!(View on GitHub (pinned to 88bb9c8533)
Solutions
- Map the status: 401 → fix api_token; 404 → fix api_url; 5xx → MoChat server side
- Probe the gateway: `curl -H "Authorization: Bearer <token>" <api_url>/api/message/receive`
- Read the `err` body text in the message — gateways usually include a reason
Defensive patterns
Strategy: try-catch
Validate before calling
let resp = client
.get(format!("{api_url}/api/message/receive"))
.header("Authorization", format!("Bearer {api_token}"))
.send()
.await?;
if !resp.status().is_success() {
return Err(anyhow::anyhow!("mochat unreachable or token invalid"));
} Try / catch
if let Err(e) = mochat.send(msg).await {
let text = e.to_string();
if text.starts_with("Mochat send message failed (401") {
// rotate api_token
} else if text.starts_with("Mochat send message failed (5") {
// gateway outage: retry with backoff
}
} Prevention
- Health-check the gateway with a cheap GET before enabling the channel
- Keep api_url and api_token in one config block validated at startup
- Distinguish HTTP failures from body-code failures when routing alerts
When it happens
Trigger: Any `send`, in-listen reply, or `health_check` with an invalid/expired api_token, a wrong api_url base path, or the MoChat gateway being down or returning 502/503.
Common situations: api_token expired or copied incorrectly; api_url missing scheme/host or pointing at the wrong service; gateway behind a proxy that returns 5xx during outages.
Related errors
- GET /users/me/channels returned {}
- login failed ({status}): {body}
- post failed ({status}): {body}
- Mochat API error (code={code}): {msg}
- Talk API error: {status}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/717b48e5bd7ac335.
Report an issue: GitHub.