{"record":{"id":"e6d65bdd80768aa6","repo":"BigPizzaV3/CodexPlusPlus","slug":"http-http-status-e6d65b","errorCode":null,"errorMessage":"发送微信回复失败：HTTP {http_status}","messagePattern":"发送微信回复失败：HTTP (.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/connect/weixin.rs","lineNumber":298,"sourceCode":"                    \"text_item\": { \"text\": text }\n                }],\n                \"context_token\": context_token\n            },\n            \"base_info\": { \"channel_version\": CHANNEL_VERSION }\n        });\n        let response = self\n            .client\n            .post(self.endpoint(\"ilink/bot/sendmessage\")?)\n            .headers(self.auth_headers()?)\n            .json(&request_body)\n            .timeout(Duration::from_secs(15))\n            .send()\n            .await\n            .context(\"发送微信回复失败\")?;\n        let (http_status, bytes) =\n            read_response_limited(response, MAX_SMALL_RESPONSE_BYTES, \"微信发送响应\").await?;\n        if !http_status.is_success() {\n            bail!(\"发送微信回复失败：HTTP {http_status}\");\n        }\n        if bytes.iter().all(u8::is_ascii_whitespace) {\n            return Ok(());\n        }\n        let result: WeixinSendResponse =\n            serde_json::from_slice(&bytes).context(\"微信发送响应格式无效\")?;\n        if result.ret != 0 || result.errcode != 0 {\n            bail!(\n                \"发送微信回复被拒绝：ret={} errcode={} {}\",\n                result.ret,\n                result.errcode,\n                result.errmsg\n            );\n        }\n        Ok(())\n    }\n\n    fn endpoint(&self, path: &str) -> anyhow::Result<reqwest::Url> {","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/f2074595a281bc057525c748175c8eb9805b0673/crates/codex-plus-core/src/connect/weixin.rs#L280-L316","documentation":"send_text POSTs one reply chunk to the sendmessage endpoint with a 15s timeout and a size-limited response; a non-2xx HTTP status fails the whole send with this error. Empty bodies on 2xx count as success, and JSON bodies with nonzero ret or errcode raise a separate rejected error, so this is purely the HTTP layer.","triggerScenarios":"The gateway rejects the send at HTTP level: expired token (401), rate limiting (429), an oversized or invalid chunk, or 5xx during maintenance.","commonSituations":"Rapid multi-chunk replies tripping rate limits; the session expired between receive and reply; ilink outage.","solutions":["Retry after backoff, especially for 429 and 5xx","Re-login when 401 or 403 persists","Slow the chunk cadence or shorten the reply text, the loop already paces 100ms between chunks","Verify the token and route headers"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for chunk in chunk_text(&reply, MAX_REPLY_CHARS) {\n    if let Err(e) = client.send_text_chunks(&peer, &chunk, token).await {\n        if e.to_string().contains(\"HTTP 4\") || e.to_string().contains(\"HTTP 5\") {\n            tokio::time::sleep(Duration::from_secs(1)).await;\n            client.send_text_chunks(&peer, &chunk, token).await?;\n        } else { return Err(e); }\n    }\n}","preventionTips":["Pace reply chunks to avoid rate limits, the loop waits 100ms per chunk","Re-login on repeated 401 or 403","Keep replies short to reduce chunk count"],"tags":["weixin","http","send","reply"],"backgroundTag":"http-error-response","analyzedSha":"f2074595a281bc057525c748175c8eb9805b0673","analyzedAt":"2026-08-23T12:52:24.489Z","contentChangedAt":"2026-08-23T12:52:24.489Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}