zeroclaw-labs/zeroclaw · error · anyhow::Error
OAuth refresh failed: {detail}
Error message
OAuth refresh failed: {detail} What it means
The Qwen OAuth token endpoint answered HTTP 2xx but the JSON body carries a non-empty `error` field, so ZeroClaw surfaces error_description (or the bare error code). Token endpoints often report soft failures like invalid_grant with a 200 status, so the status check alone cannot classify the failure. The refresh aborts and provider construction fails.
Source
Thrown at crates/zeroclaw-providers/src/lib.rs:358
ERROR,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)
.with_outcome(::zeroclaw_log::EventOutcome::Failure)
.with_attrs(::serde_json::json!({
"oauth_provider": "qwen",
"phase": "refresh_parse",
})),
"qwen: OAuth refresh response is not JSON"
);
anyhow::Error::msg("OAuth refresh response is not JSON")
})?;
if let Some(error_code) = payload
.error
.as_deref()
.filter(|value| !value.trim().is_empty())
{
let detail = payload.error_description.as_deref().unwrap_or(error_code);
anyhow::bail!("OAuth refresh failed: {detail}");
}
let access_token = payload
.access_token
.as_deref()
.map(str::trim)
.filter(|token| !token.is_empty())
.ok_or_else(|| {
::zeroclaw_log::record!(
ERROR,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)
.with_outcome(::zeroclaw_log::EventOutcome::Failure)
.with_attrs(::serde_json::json!({
"oauth_provider": "qwen",
"field": "access_token",
})),
"qwen: OAuth refresh response missing access_token"
);View on GitHub (pinned to 88bb9c8533)
Solutions
- Re-login with `qwen login` to replace the refresh token
- Read error_description: invalid_grant means re-auth; invalid_client means a client_id mismatch — upgrade ZeroClaw
- Delete ~/.qwen/oauth_creds.json if it is corrupted, then log in again
Defensive patterns
Strategy: try-catch
Try / catch
match refresh_qwen_oauth_access_token(&token, &client_id) {
Err(e) => {
let msg = e.to_string();
if msg.contains("invalid_grant") || msg.contains("expired") {
return Reauth::required("qwen login"); // refresh token is dead
}
if msg.contains("invalid_client") { return Upgrade::required(); }
Err(e)
}
ok => ok,
} Prevention
- Expect soft OAuth failures with HTTP 200 — always inspect error/error_description, not just status
- Re-login as soon as invalid_grant appears; repeated refresh attempts can lock the token
- Delete corrupted oauth_creds.json rather than looping on refresh
When it happens
Trigger: Refresh response body such as `{"error":"invalid_grant","error_description":"refresh token expired"}` with HTTP 200; invalid_client or bad client_id delivered the same way.
Common situations: Refresh token revoked after logout or password change on the Qwen side; ZeroClaw version drift changing the expected client_id; partially corrupted oauth_creds.json with a malformed refresh_token.
Related errors
- OAuth refresh failed (HTTP {status}): {detail}
- QQ token request failed ({status}): {err}
- token refresh failed ({status}): {body}
- MiniMax OAuth refresh failed (HTTP {status}): {detail}
- MiniMax OAuth refresh failed: {detail}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/64fed971ea506f32.
Report an issue: GitHub.