jlcodes99/cockpit-tools · error
OAuth 回调服务器错误: {}
Error message
OAuth 回调服务器错误: {} What it means
OAuth callback server failure log inside the restored listener spawned by ensure_callback_listener_for_state (src-tauri/src/modules/codex_oauth.rs:234). For a persisted OAuthState without a device_auth_id, the module re-binds the saved callback port and spawns start_callback_server on a tokio task; if that server task returns Err, this line logs it. The OAuth login flow then cannot receive the browser redirect callback, so the pending login will eventually time out. Called from start_oauth_login and restore_pending_oauth_listener.
Source
Thrown at src-tauri/src/modules/codex_oauth.rs:234
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
- Check whether another process is listening on the callback port (e.g. `lsof -iTCP:<port>` / `netstat -ano`) and kill it or change OAUTH_CALLBACK_PORT
- Restart the OAuth login (start_oauth_login) to obtain a fresh state and re-establish the listener
- Disable or configure antivirus/firewall software that blocks loopback socket binds
- If the state expired, note that ensure_callback_listener_for_state clears it when expires_at <= now — just log in again
- Retry after closing other instances of the app that may race for the same port
Example fix
// before: fire-and-forget callback server, failure only logged
tokio::spawn(async move {
if let Err(e) = start_callback_server(port, state, login_id, url, handle).await {
log_error("OAuth 回调服务器错误: {}", e);
}
});
// after: probe the bind inside the task and report the failure to the UI
tokio::spawn(async move {
match start_callback_server(port, state, login_id, url, handle.clone()).await {
Ok(()) => {}
Err(e) => {
log_error("OAuth 回调服务器错误: {}", e);
let _ = handle.emit("codex:oauth-callback-error", serde_json::json!({
"login_id": login_id, "port": port, "error": e
}));
}
}
}); Defensive patterns
Strategy: try-catch
Validate before calling
use std::net::TcpListener;
fn callback_port_available(port: u16) -> bool {
TcpListener::bind(("127.0.0.1", port)).map(|l| drop(l)).is_ok()
}
// check before starting/restoring OAuth login: callback_port_available(state.port) Type guard
fn listener_restorable(state: &OAuthState) -> bool {
state.device_auth_id.is_none() && state.expires_at > now_timestamp()
} Try / catch
match start_oauth_login(app_handle).await {
Ok(login_id) => println!("OAuth 登录已启动: {login_id}"),
Err(e) if e.contains("端口被占用") || e.contains("port in use") => {
eprintln!("回调端口被占用,请关闭占用进程后重试: {e}");
}
Err(e) => eprintln!("OAuth 登录失败: {e}"),
} Prevention
- Check the callback port is free (and not held by another app instance) before initiating OAuth login
- Configure antivirus/firewall to allow loopback binds on 127.0.0.1
- Avoid running multiple app instances concurrently during OAuth login
- If login seems stuck, restart the flow to get a fresh state before the persisted expires_at passes
When it happens
Trigger: start_callback_server(port, expected_state, expected_login_id, callback_url, ...) returning Err after the pre-bind probe succeeded — e.g. another process steals port 127.0.0.1:callback_port between the probe and the server bind, the listener is closed unexpectedly, an internal accept/bind error occurs, or the tokio runtime fails to accept connections.
Common situations: Antivirus/firewall blocking loopback binds; another instance of the app (or Codex CLI) already holding the callback port in a state that passed the probe; port reused by an unrelated dev server on 127.0.0.1; the persisted OAuthState restored after app restart while a stale server still occupies the port; corporate security software intercepting loopback HTTP.
Related errors
- OAuth 回调服务器错误: {}
- 本地回调服务异常: {}
- [Windsurf OAuth] 回调服务恢复失败: login_id={}, error={}
- [Windsurf OAuth] 回调服务异常: login_id={}, error={}
- Claude OAuth start 响应缺少关键字段
AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05).
Data as JSON: /api/errors/3a9986915b03dbca.
Report an issue: GitHub.