zeroclaw-labs/zeroclaw · error · anyhow::Error
Mochat API error (code={code}): {msg}
Error message
Mochat API error (code={code}): {msg} What it means
MoChat answers HTTP 200 but carries a business status in the JSON body; this error fires when that `code` is anything other than 0 or 200. The `msg`/`message` field from the body is included (defaulting to "unknown error" when absent). Typical causes are an unknown `toUserId` recipient or content the gateway refuses.
Source
Thrown at crates/zeroclaw-channels/src/mochat.rs:132
.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!(
INFO,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note),
"starting message poller"
);
let poll_interval = std::time::Duration::from_secs(self.poll_interval_secs);
let mut last_message_id: Option<String> = None;
loop {
let mut url = format!("{}/api/message/receive", self.api_url);
if let Some(ref id) = last_message_id {View on GitHub (pinned to 88bb9c8533)
Solutions
- Read the `msg` — it states the business failure verbatim from the gateway
- Verify the recipient's toUserId exists in the MoChat system
- Look up the numeric code in the MoChat gateway API docs
- Retry only when the msg indicates a transient condition
Defensive patterns
Strategy: try-catch
Try / catch
if let Err(e) = mochat.send(msg).await {
let text = e.to_string();
if text.starts_with("Mochat API error") {
// business rejection: surface the msg text to the user; do not blind-retry
}
} Prevention
- Validate recipient IDs at ingestion before attempting sends
- Keep a mapping of known MoChat business codes to user-facing messages
- Log the code+msg pair — the gateway text is the only actionable detail
When it happens
Trigger: `Channel::send` where the HTTP layer succeeded but the body `code` is e.g. a recipient error: `toUserId` (message.recipient) does not exist, is not provisioned, or the content violates a gateway rule.
Common situations: Recipient user ID typo'd; recipient not registered in MoChat; gateway limits (length, rate) expressed as business codes.
Related errors
- Mochat send message failed ({status}): {err}
- Gmail OAuth token is not configured for sending
- post failed ({status}): {body}
- Talk API error: {status}
- Mochat channel requires the `channel-mochat` feature
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/ec814bf93067c6ab.
Report an issue: GitHub.