jlcodes99/cockpit-tools · error

OAuth 回调服务器错误: {}

Error message

OAuth 回调服务器错误: {}

What it means

When restoring a pending Codex OAuth session, ensure_callback_listener_for_state spawns a background task that runs the local HTTP callback server. If that server task returns an error (bind failure, port conflict, handler crash), it is logged as 'OAuth 回调服务器错误'. The OAuth flow cannot receive the provider's redirect until this server is listening.

Source

Thrown at crates/cockpit-core/src/modules/codex_oauth.rs:228

    match TcpListener::bind(("127.0.0.1", state.port)) {
        Ok(listener) => {
            drop(listener);
            let expected_state = state.state.clone();
            let expected_login_id = state.login_id.clone();
            let callback_url = state.redirect_uri.clone();
            let app_handle_clone = app_handle.clone();
            let port = state.port;
            tokio::spawn(async move {
                if let Err(e) = start_callback_server(
                    port,
                    expected_state,
                    expected_login_id,
                    callback_url,
                    app_handle_clone,
                )
                .await
                {
                    logger::log_error(&format!("OAuth 回调服务器错误: {}", e));
                }
            });
            logger::log_info(&format!(
                "Codex OAuth 已恢复回调监听: login_id={}, port={}",
                state.login_id, state.port
            ));
        }
        Err(err) if err.kind() == ErrorKind::AddrInUse => {
            logger::log_info(&format!(
                "Codex OAuth 回调端口已占用,视为监听中: login_id={}, port={}",
                state.login_id, state.port
            ));
        }
        Err(err) => {
            logger::log_warn(&format!(
                "Codex OAuth 回调监听恢复失败: login_id={}, port={}, error={}",
                state.login_id, state.port, err
            ));

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Check whether the callback port is occupied (lsof -i :<port> / netstat) and free it or restart the conflicting service
  2. Clear/restart the pending OAuth login so a fresh port is allocated
  3. Retry start_oauth_login to create a new session and listener
  4. Check firewall/antivirus rules that may block binding a local HTTP listener
Defensive patterns

Strategy: try-catch

Validate before calling

// before restoring, check the port is bindable
use std::net::TcpListener;
fn port_free(port: u16) -> bool {
    TcpListener::bind(("127.0.0.1", port)).is_ok()
}

Try / catch

match restore_pending_oauth_listener(app).await {
    Ok(_) => {},
    Err(e) if format!("{e}").contains("OAuth 回调服务器错误") => {
        // port blocked/stale state: clear pending state and start a fresh login
        clear_pending_oauth_state(app);
        start_oauth_login(app).await?;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: App restart with a persisted OAuth state whose port is now occupied by another process; firewall blocking the local listener; bind to 127.0.0.1:<port> failing because the port is in TIME_WAIT or reserved.

Common situations: Port taken by another instance of the app or unrelated service after reboot; stale pending OAuth state restored long after the session expired; security software blocking local socket binding.

Related errors


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