jlcodes99/cockpit-tools · error

Codex OAuth completed 命令失败: login_id={}, duration_ms={}, err

Error message

Codex OAuth completed 命令失败: login_id={}, duration_ms={}, error={}

What it means

This error is logged when the frontend-invoked codex_oauth_completed command fails to finalize a Codex OAuth login: complete_oauth_login(&login_id) returned Err after the browser flow finished. The pending login state (matched by login_id and started_at_ms) could not be exchanged/validated into tokens, and the error is propagated back to the caller.

Source

Thrown at src-tauri/src/commands/codex_account_commands.rs:1949

) -> Result<(), String> {
    codex_oauth::open_incognito_oauth_window(&app_handle, &auth_url)
}

/// OAuth:浏览器授权完成后按 loginId 完成登录
#[tauri::command]
pub async fn codex_oauth_login_completed(
    login_id: String,
    reauth_account_id: Option<String>,
) -> Result<CodexAccount, String> {
    let started_at_ms = chrono::Utc::now().timestamp_millis();
    logger::log_info(&format!(
        "Codex OAuth completed 命令开始: login_id={}, started_at_ms={}",
        login_id, started_at_ms
    ));
    let tokens = match codex_oauth::complete_oauth_login(&login_id).await {
        Ok(tokens) => tokens,
        Err(e) => {
            logger::log_error(&format!(
                "Codex OAuth completed 命令失败: login_id={}, duration_ms={}, error={}",
                login_id,
                chrono::Utc::now().timestamp_millis() - started_at_ms,
                e
            ));
            return Err(e);
        }
    };
    let account = save_codex_oauth_tokens(tokens, reauth_account_id.as_deref()).await?;
    logger::log_info(&format!(
        "Codex OAuth completed 命令成功: login_id={}, duration_ms={}, account_id={}, account_email={}",
        login_id,
        chrono::Utc::now().timestamp_millis() - started_at_ms,
        account.id,
        account.email
    ));
    Ok(account)
}

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Restart the OAuth flow from the beginning (start a fresh login to get a new login_id) rather than retrying the completed call
  2. Check the elapsed duration_ms in the log — a large value means the pending login likely expired; complete the flow faster
  3. Ensure the app isn't restarted between the OAuth start and completion steps
  4. Inspect the wrapped error detail to see if it's a state mismatch (double-click/duplicate flow) vs upstream token-exchange failure

Example fix

// before
let tokens = match codex_oauth::complete_oauth_login(&login_id).await {
    Ok(tokens) => tokens,
    Err(e) => {
        logger::log_error(&format!("Codex OAuth completed 命令失败: login_id={}, duration_ms={}, error={}", login_id, chrono::Utc::now().timestamp_millis() - started_at_ms, e));
        return Err(e);
    }
};
// after
let tokens = match codex_oauth::complete_oauth_login(&login_id).await {
    Ok(tokens) => tokens,
    Err(e) => {
        logger::log_error(&format!("Codex OAuth completed 命令失败: login_id={}, duration_ms={}, error={}", login_id, chrono::Utc::now().timestamp_millis() - started_at_ms, e));
        // clear the dead pending state so the UI can start a clean flow immediately
        let _ = codex_oauth::clear_pending_login(&login_id).await;
        return Err(format!("OAuth 完成失败,请重新发起登录: {}", e));
    }
};
Defensive patterns

Strategy: try-catch

Validate before calling

// before calling completed, confirm the pending login still exists and is fresh
if !codex_oauth::has_pending_login(&login_id) {
    return Err("登录会话不存在或已失效,请重新发起登录".to_string());
}
if started_at_ms.elapsed_ms() > PENDING_LOGIN_TTL_MS {
    return Err("登录会话已超时,请重新发起登录".to_string());
}

Try / catch

match codex_oauth::complete_oauth_login(&login_id).await {
    Ok(tokens) => tokens,
    Err(e) => {
        let _ = codex_oauth::clear_pending_login(&login_id); // avoid stuck state
        return Err(format!("OAuth 完成失败,请重新发起登录: {}", e));
    }
}

Prevention

When it happens

Trigger: complete_oauth_login(login_id) fails because the pending login expired or was never registered, the state token mismatched, the authorization code/token exchange with the Codex OAuth endpoint returned an error, or the callback server stored no result for that login_id.

Common situations: User took too long between starting login and completing authorization (pending state expired); user restarted the app between start and completed calls (in-memory pending login lost); clicking the login button twice so a stale login_id is completed; upstream auth server returning 4xx/5xx on token exchange.

Related errors


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