{"record":{"id":"ec814bf93067c6ab","repo":"zeroclaw-labs/zeroclaw","slug":"mochat-api-error-code-code-msg","errorCode":null,"errorMessage":"Mochat API error (code={code}): {msg}","messagePattern":"Mochat API error \\(code=(.+?)\\): (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/mochat.rs","lineNumber":132,"sourceCode":"            .json(&body)\n            .send()\n            .await?;\n\n        if !resp.status().is_success() {\n            let status = resp.status();\n            let err = resp.text().await.unwrap_or_default();\n            anyhow::bail!(\"Mochat send message failed ({status}): {err}\");\n        }\n\n        let result: serde_json::Value = resp.json().await?;\n        let code = result.get(\"code\").and_then(|v| v.as_i64()).unwrap_or(-1);\n        if code != 0 && code != 200 {\n            let msg = result\n                .get(\"msg\")\n                .or_else(|| result.get(\"message\"))\n                .and_then(|v| v.as_str())\n                .unwrap_or(\"unknown error\");\n            anyhow::bail!(\"Mochat API error (code={code}): {msg}\");\n        }\n\n        Ok(())\n    }\n\n    async fn listen(&self, tx: tokio::sync::mpsc::Sender<ChannelMessage>) -> anyhow::Result<()> {\n        ::zeroclaw_log::record!(\n            INFO,\n            ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note),\n            \"starting message poller\"\n        );\n\n        let poll_interval = std::time::Duration::from_secs(self.poll_interval_secs);\n        let mut last_message_id: Option<String> = None;\n\n        loop {\n            let mut url = format!(\"{}/api/message/receive\", self.api_url);\n            if let Some(ref id) = last_message_id {","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/mochat.rs#L114-L150","documentation":"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.","triggerScenarios":"`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.","commonSituations":"Recipient user ID typo'd; recipient not registered in MoChat; gateway limits (length, rate) expressed as business codes.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = mochat.send(msg).await {\n    let text = e.to_string();\n    if text.starts_with(\"Mochat API error\") {\n        // business rejection: surface the msg text to the user; do not blind-retry\n    }\n}","preventionTips":["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"],"tags":["mochat","send","api-error-code","rust"],"backgroundTag":"api-business-error","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}