jlcodes99/cockpit-tools · error
Authorization expired
Error message
Authorization expired
What it means
send_stream_request calls the Cloud Code streaming endpoint with an access_token; on HTTP 401 UNAUTHORIZED it returns the fixed error string 'Authorization expired'. This means the bearer token was rejected — it is missing, malformed, or no longer valid — and the code deliberately stops retrying since retrying with the same token cannot succeed.
Source
Thrown at src-tauri/src/modules/wakeup.rs:532
if delay > 0 {
crate::modules::logger::log_info(&format!(
"[Wakeup] 准备重试: delay={}ms",
delay
));
sleep_with_cancel(
std::time::Duration::from_millis(delay),
cancel_rx,
)
.await?;
}
continue;
}
}
}
} else {
if status == reqwest::StatusCode::UNAUTHORIZED {
crate::modules::logger::log_error("[Wakeup] 授权失效 (401)");
return Err("Authorization expired".to_string());
}
if status == reqwest::StatusCode::FORBIDDEN {
crate::modules::logger::log_error("[Wakeup] 无权限 (403)");
return Err("Cloud Code access forbidden".to_string());
}
let text = await_with_cancel(cancel_rx, res.text())
.await?
.unwrap_or_default();
let retryable = status == reqwest::StatusCode::TOO_MANY_REQUESTS
|| status.as_u16() >= 500;
let message = format!("唤醒请求失败: {} - {}", status, text);
last_error = Some(message.clone());
crate::modules::logger::log_warn(&format!(
"[Wakeup] 请求失败: url={}, status={}, retryable={}",
url, status, retryable
));
if retryable && attempt < DEFAULT_ATTEMPTS {
let delay = get_backoff_delay_ms(attempt + 1);View on GitHub (pinned to 1ed8b77992)
Solutions
- Trigger a token refresh (or re-authentication) before the next wakeup attempt
- Verify the access_token being attached is present and for the correct base URL/environment
- Have the user log in again if refresh_token is missing or also revoked
- Check device clock sync if tokens seem to expire instantly
- Inspect base_url order — a 401 from one mirror may be environment-specific
Example fix
// before
if status == reqwest::StatusCode::UNAUTHORIZED {
return Err("Authorization expired".to_string());
}
// after
if status == reqwest::StatusCode::UNAUTHORIZED {
if refresh_access_token().await.is_ok() {
continue; // retry with new token
}
return Err("Authorization expired".to_string());
} Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight: ensure a token exists and refresh proactively if near expiry
if access_token.is_empty() || token_expires_in_secs() < 60 {
refresh_access_token().await.expect("refresh failed; user must re-login");
} Type guard
fn is_auth_expired(err: &str) -> bool { err == "Authorization expired" } Try / catch
match trigger_wakeup_direct(...).await {
Err(e) if e == "Authorization expired" => {
if refresh_access_token().await.is_ok() {
retry_once().await; // single retry with fresh token
} else {
prompt_relogin();
}
}
other => handle(other),
} Prevention
- Refresh tokens proactively before expiry (e.g. at 80% lifetime)
- Handle refresh failures by prompting re-login instead of hammering 401s
- Keep device clocks synchronized (NTP)
- Persist tokens securely and per-environment to avoid cross-env 401s
When it happens
Trigger: trigger_wakeup_direct → send_stream_request receives a 401 from the wakeup/stream API while carrying the stored access_token.
Common situations: Token expired after long idle; refresh flow failed silently or never ran; user logged out/revoked access server-side; token for the wrong environment (staging vs prod base URL); clock skew making a valid token appear expired.
Related errors
- 刷新 Codex 账号资料失败:
- Claude OAuth start 响应缺少关键字段
- Qoder OAuth 授权链接为空
- [WebDAV] Auto backup upload failed
- [TraeAutoCheckin] 账号 ${account.id} 签到异常:
AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05).
Data as JSON: /api/errors/50d1c01d658f05bf.
Report an issue: GitHub.