jlcodes99/cockpit-tools · error

获取用户信息失败: {}

Error message

获取用户信息失败: {}

What it means

After obtaining OAuth tokens, start_oauth_login calls modules::oauth::get_user_info(&token_res.access_token) to fetch the Google account profile (email, display name). This error is logged and returned when that userinfo API call fails, aborting account creation since the account is keyed by email.

Source

Thrown at src-tauri/src/commands/oauth.rs:77

    modules::logger::log_info("OAuth 授权成功,检查 refresh_token...");

    let refresh_token = token_res.refresh_token.ok_or_else(|| {
        let msg = "未获取到 Refresh Token。\n\n\
         可能原因:您之前已授权过此应用\n\n\
         解决方案:\n\
         1. 访问 https://myaccount.google.com/permissions\n\
         2. 撤销 'Antigravity Tools' 的访问权限\n\
         3. 重新进行 OAuth 授权"
            .to_string();
        modules::logger::log_error(&msg);
        msg
    })?;

    modules::logger::log_info("获取用户信息...");
    let user_info = modules::oauth::get_user_info(&token_res.access_token)
        .await
        .map_err(|e| {
            modules::logger::log_error(&format!("获取用户信息失败: {}", e));
            e
        })?;

    modules::logger::log_info(&format!(
        "用户: {} ({})",
        user_info.email,
        user_info.name.as_deref().unwrap_or("无名称")
    ));

    let token_data = models::TokenData::new(
        token_res.access_token,
        refresh_token,
        token_res.expires_in,
        Some(user_info.email.clone()),
        None,
        user_info.id.clone(),
    )
    .with_oauth_metadata(token_res.oauth_client_key, token_res.id_token);

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Check that the OAuth request includes the userinfo.email and userinfo.profile scopes, then re-run authorization
  2. Verify network connectivity / proxy settings and retry the login
  3. Check the wrapped error detail: 401 means re-authenticate; 403 means missing scope; 5xx/timeout means retry later
  4. Confirm the access token is used promptly after exchange and not cached stale

Example fix

// before
let user_info = modules::oauth::get_user_info(&token_res.access_token)
    .await
    .map_err(|e| {
        modules::logger::log_error(&format!("获取用户信息失败: {}", e));
        e
    })?;
// after
let user_info = modules::oauth::get_user_info(&token_res.access_token)
    .await
    .map_err(|e| {
        modules::logger::log_error(&format!("获取用户信息失败: {}", e));
        if e.contains("401") || e.contains("403") {
            format!("访问令牌无效或权限不足,请重新授权: {}", e)
        } else {
            format!("获取用户信息失败,请检查网络后重试: {}", e)
        }
    })?;
Defensive patterns

Strategy: retry

Validate before calling

// ensure the token exchange requested the scopes needed for userinfo
if !granted_scopes.contains("userinfo.email") || !granted_scopes.contains("userinfo.profile") {
    return Err("授权缺少 userinfo 权限,请重新授权并勾选完整权限".to_string());
}

Try / catch

let user_info = match modules::oauth::get_user_info(&token_res.access_token).await {
    Ok(u) => u,
    Err(e) if is_auth_error(&e) => return Err(format!("访问令牌无效或权限不足,请重新授权: {}", e)),
    Err(e) if is_transient(&e) => match modules::oauth::get_user_info(&token_res.access_token).await {
        Ok(u) => u,
        Err(e2) => return Err(format!("获取用户信息失败,请检查网络后重试: {}", e2)),
    },
    Err(e) => return Err(format!("获取用户信息失败: {}", e)),
};

Prevention

When it happens

Trigger: get_user_info(access_token) returns Err: the userinfo endpoint returned 401/403 (invalid or insufficient-scope access token), a network/timeout error, or an unparseable response.

Common situations: OAuth scope not including userinfo.profile/userinfo.email so Google rejects the userinfo call; access token already expired or revoked by the time the call runs; offline/proxy/network interruption; Google userinfo endpoint outage.

Related errors


AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05). Data as JSON: /api/errors/ac0dc6ff891202b6. Report an issue: GitHub.