{"record":{"id":"8c888483e090e16e","repo":"zeroclaw-labs/zeroclaw","slug":"glm-api-error-error","errorCode":null,"errorMessage":"GLM API error: {error}","messagePattern":"GLM API error: (.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/glm.rs","lineNumber":196,"sourceCode":"        let request = ChatRequest {\n            model: model.to_string(),\n            messages,\n            temperature,\n        };\n\n        let url = format!(\"{}/chat/completions\", self.base_url);\n\n        let response = self\n            .http_client()\n            .post(&url)\n            .header(\"Authorization\", format!(\"Bearer {token}\"))\n            .json(&request)\n            .send()\n            .await?;\n\n        if !response.status().is_success() {\n            let error = response.text().await?;\n            anyhow::bail!(\"GLM API error: {error}\");\n        }\n\n        let chat_response: ChatResponse = response.json().await?;\n\n        chat_response\n            .choices\n            .into_iter()\n            .next()\n            .map(|c| c.message.content)\n            .ok_or_else(|| {\n                ::zeroclaw_log::record!(\n                    ERROR,\n                    ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)\n                        .with_outcome(::zeroclaw_log::EventOutcome::Failure),\n                    \"glm: empty choices in response\"\n                );\n                anyhow::Error::msg(\"No response from GLM\")\n            })","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/glm.rs#L178-L214","documentation":"chat_with_system POSTed to {base_url}/chat/completions and got a non-2xx; the raw response body is embedded verbatim after 'GLM API error:'. The body distinguishes bad JWT/key (401), unknown model, rate limit (429), and context overflow.","triggerScenarios":"Calling chat_with_system with an unsupported model id for the GLM endpoint; a mis-signed or clock-skewed JWT (tokens expire after 3.5 minutes); 429 rate limiting; a base_url override pointing at an incompatible proxy.","commonSituations":"Upstream model rename (glm-4 era ids retired); host clock skew breaking the exp claim; corporate proxy rewriting responses; quota exhausted on the Z.ai plan.","solutions":["Read the embedded body: 401 -> verify the id.secret key; model-not-found -> use a current model id; 429 -> back off","Verify the system clock (JWT exp depends on it)","Restore the default base_url https://api.z.ai/api/paas/v4 unless using a compatible gateway","Retry with backoff only for 429/5xx-class bodies"],"exampleFix":"// before\nlet text = provider.chat_with_system(None, prompt, model, temp).await?;\n\n// after\nlet text = match provider.chat_with_system(None, prompt, model, temp).await {\n    Ok(t) => t,\n    Err(e) if e.to_string().contains(\"429\") => {\n        tokio::time::sleep(std::time::Duration::from_secs(10)).await;\n        provider.chat_with_system(None, prompt, model, temp).await?\n    }\n    Err(e) => return Err(e),\n};","handlingStrategy":"try-catch","validationCode":"fn glm_credentials_ready() -> bool {\n    std::env::var(\"GLM_API_KEY\").map(|k| glm_key_valid(&k)).unwrap_or(false)\n}","typeGuard":"fn is_glm_http_error(e: &anyhow::Error) -> bool {\n    e.to_string().starts_with(\"GLM API error: \")\n}","tryCatchPattern":"match provider.chat_with_system(None, prompt, model, temp).await {\n    Ok(t) => Ok(t),\n    Err(e) => {\n        let msg = e.to_string();\n        if msg.contains(\"429\") || msg.contains(\"500\") {\n            backoff_and_retry().await\n        } else {\n            Err(anyhow::anyhow!(\"GLM call failed: {msg}\")) // auth/model: fix config\n        }\n    }\n}","preventionTips":["Keep NTP healthy on hosts issuing GLM JWTs (3.5-minute expiry)","Verify model ids against the current GLM catalog when upgrading","Retain the embedded body in logs; it is the authoritative diagnostic","Wrap batch jobs with per-request backoff for 429s"],"tags":["rust","zeroclaw","glm","http-status","api-error","jwt"],"backgroundTag":"llm-api-http-error","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}