{"record":{"id":"c40cbff95de59abe","repo":"zeroclaw-labs/zeroclaw","slug":"tenant-access-token-failed-msg","errorCode":null,"errorMessage":"tenant_access_token failed: {msg}","messagePattern":"tenant_access_token failed: (.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/zeroclaw-channels/src/lark.rs","lineNumber":1506,"sourceCode":"            \"app_id\": self.app_id,\n            \"app_secret\": self.app_secret,\n        });\n\n        let resp = self.http_client().post(&url).json(&body).send().await?;\n        let status = resp.status();\n        let data: serde_json::Value = resp.json().await?;\n\n        if !status.is_success() {\n            anyhow::bail!(\"tenant_access_token request failed: status={status}, body={data}\");\n        }\n\n        let code = data.get(\"code\").and_then(|c| c.as_i64()).unwrap_or(-1);\n        if code != 0 {\n            let msg = data\n                .get(\"msg\")\n                .and_then(|m| m.as_str())\n                .unwrap_or(\"unknown error\");\n            anyhow::bail!(\"tenant_access_token failed: {msg}\");\n        }\n\n        let token = data\n            .get(\"tenant_access_token\")\n            .and_then(|t| t.as_str())\n            .ok_or_else(|| {\n                ::zeroclaw_log::record!(\n                    WARN,\n                    ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)\n                        .with_outcome(::zeroclaw_log::EventOutcome::Failure),\n                    \"missing tenant_access_token in response\"\n                );\n                anyhow::Error::msg(\"missing tenant_access_token in response\")\n            })?\n            .to_string();\n\n        let ttl_seconds = extract_lark_token_ttl_seconds(&data);\n        let refresh_after = next_token_refresh_deadline(Instant::now(), ttl_seconds);","sourceCodeStart":1488,"sourceCodeEnd":1524,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/lark.rs#L1488-L1524","documentation":"The tenant_access_token endpoint returned HTTP 2xx, but the JSON body carried a non-zero Lark business code. Lark reports application errors as {\"code\": ..., \"msg\": ...} even with a 200 status; this variant almost always means the credentials themselves are wrong or the app is gone. The msg from the body is included (\"unknown error\" if the field is missing), and code=-1 appears when no code field could be parsed.","triggerScenarios":"Invalid or revoked app_id/app_secret, an app that was deleted or disabled in the Lark developer console, a secret with trailing whitespace/newline/quotes copied from the console, or credentials from a different app pasted into config.","commonSituations":"The app secret was rotated in the Lark console but the config was never updated; the App ID was pasted into the app_secret field; environment-specific credentials (dev vs prod app) got mixed; secret stored with surrounding quotes or a newline.","solutions":["Re-copy both App ID and App Secret from the Lark developer console (Credentials page) and update [channels.lark.<alias>] exactly.","Inspect the secret for stray whitespace, quotes, or newlines and strip them.","Confirm the app still exists, is enabled, and has not been deleted.","After fixing credentials, restart the channel so it drops any cached token state."],"exampleFix":"# before (TOML config)\n[channels.lark.main]\napp_id = \"cli_a1b2c3\"\napp_secret = \"\\\"xYz...secret...\\\"\\n\"   # pasted with quotes and trailing newline\n\n# after\n[channels.lark.main]\napp_id = \"cli_a1b2c3\"\napp_secret = \"xYz...secret...\"","handlingStrategy":"validation","validationCode":"// Fail fast at startup on bad credentials instead of mid-conversation\nlet token = lark.get_tenant_access_token().await\n    .context(\"Lark credentials rejected at startup; check app_id/app_secret in [channels.lark.<alias>]\")?;","typeGuard":null,"tryCatchPattern":"if let Err(e) = lark.get_tenant_access_token().await {\n    if e.to_string().contains(\"tenant_access_token failed\") {\n        // business-code rejection: do NOT retry; credentials are wrong\n        return Err(e.context(\"fix Lark app credentials before retrying\"));\n    }\n    return Err(e);\n}","preventionTips":["Run a startup health check that fetches one tenant_access_token before accepting traffic.","Store secrets via a secret manager; never hand-edit them in config files where whitespace sneaks in.","When rotating the Lark app secret, update config and restart in the same change."],"tags":["lark","feishu","credentials","invalid-secret","authentication"],"backgroundTag":"invalid-api-credentials","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}