{"record":{"id":"e3f63591c84dec0b","repo":"zeroclaw-labs/zeroclaw","slug":"minimax-oauth-refresh-response-missing-access-toke","errorCode":null,"errorMessage":"MiniMax OAuth refresh response missing access_token","messagePattern":"MiniMax OAuth refresh response missing access_token","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/lib.rs","lineNumber":502,"sourceCode":"            && !status_text.eq_ignore_ascii_case(\"success\")\n        {\n            let detail = payload\n                .base_resp\n                .as_ref()\n                .and_then(|base| base.status_msg.as_deref())\n                .unwrap_or(status_text);\n            anyhow::bail!(\"MiniMax OAuth refresh failed: {detail}\");\n        }\n        if let Some(token) = payload\n            .access_token\n            .as_deref()\n            .map(str::trim)\n            .filter(|token| !token.is_empty())\n        {\n            return Ok(token.to_string());\n        }\n    }\n    anyhow::bail!(\"MiniMax OAuth refresh response missing access_token\")\n}\n\nfn resolve_qwen_oauth_context(credential_override: Option<&str>) -> QwenOauthProviderContext {\n    let override_value = credential_override\n        .map(str::trim)\n        .filter(|value| !value.is_empty());\n    let placeholder_requested = override_value\n        .map(|value| value.eq_ignore_ascii_case(QWEN_OAUTH_PLACEHOLDER))\n        .unwrap_or(false);\n\n    if let Some(explicit) = override_value\n        && !placeholder_requested\n    {\n        return QwenOauthProviderContext {\n            credential: Some(explicit.to_string()),\n            base_url: None,\n        };\n    }","sourceCodeStart":484,"sourceCodeEnd":520,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/lib.rs#L484-L520","documentation":"The MiniMax refresh response was HTTP 2xx, JSON-parseable, and reported a success status (or had none), but contained no non-empty access_token string. With nothing to authenticate subsequent requests, refresh fails. This is the terminal fallback of refresh_minimax_oauth_access_token after the status and error paths pass.","triggerScenarios":"Response body like `{\"status\":\"success\"}` with the access_token field missing, null, or whitespace-only; an HTML or empty body that still parsed as all-optional fields (every field of MinimaxOauthRefreshResponse is optional).","commonSituations":"Upstream API contract change renaming the token field; gateway or proxy stripping the response body; endpoints returning an unexpected envelope shape after a MiniMax API revision.","solutions":["Capture the raw refresh response (proxy or debug logging) and compare it with the documented MiniMax token response","If the field was renamed upstream, upgrade ZeroClaw or file an issue with the observed payload shape","Retry once to rule out a truncated response from an intermediary","Reissue the refresh token if the account state is suspected corrupt"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match refresh_minimax_oauth_access_token(&token, &client_id, region) {\n    Err(e) if e.to_string().ends_with(\"missing access_token\") => {\n        // contract change or truncated body: log the raw exchange once, then fail loudly\n        log::error!(\"MiniMax token response shape changed: {e}\");\n        Err(e)\n    }\n    other => other,\n}","preventionTips":["Log one raw refresh response when this fires — the payload shape is the evidence","Pin API versions or provider releases after MiniMax contract changes","Do not accept an empty access_token as success anywhere downstream"],"tags":["minimax","oauth","refresh-token","missing-field","api-contract"],"backgroundTag":"oauth-refresh-token-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}