{"record":{"id":"bdfed8df05ebdf8a","repo":"jlcodes99/cockpit-tools","slug":"error-bdfed8","errorCode":null,"errorMessage":"本地回调服务异常: {}","messagePattern":"本地回调服务异常: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cockpit-core/src/modules/kiro_oauth.rs","lineNumber":134,"sourceCode":"    if state.callback_result.is_some() {\n        return;\n    }\n\n    match TcpListener::bind((\"127.0.0.1\", state.callback_port)) {\n        Ok(listener) => {\n            drop(listener);\n            let expected_login_id = state.login_id.clone();\n            let expected_state = state.state_token.clone();\n            let callback_port = state.callback_port;\n            tokio::spawn(async move {\n                if let Err(err) = start_callback_server(\n                    callback_port,\n                    expected_login_id.clone(),\n                    expected_state.clone(),\n                )\n                .await\n                {\n                    logger::log_error(&format!(\n                        \"[Kiro OAuth] 回调服务恢复失败: login_id={}, error={}\",\n                        expected_login_id, err\n                    ));\n                    set_callback_result_for_login(\n                        &expected_login_id,\n                        &expected_state,\n                        Err(format!(\"本地回调服务异常: {}\", err)),\n                    );\n                }\n            });\n            logger::log_info(&format!(\n                \"[Kiro OAuth] 已恢复本地回调服务: login_id={}, port={}\",\n                state.login_id, state.callback_port\n            ));\n        }\n        Err(err) if err.kind() == ErrorKind::AddrInUse => {\n            logger::log_info(&format!(\n                \"[Kiro OAuth] 本地回调端口已占用，视为监听中: login_id={}, port={}\",","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/crates/cockpit-core/src/modules/kiro_oauth.rs#L116-L152","documentation":"Logged during restore_pending_oauth_listener when re-creating the Kiro OAuth local HTTP callback server (for a pending login identified by login_id/state) fails. The error is stored as the callback result for that login, so any client waiting on the login future receives \"本地回调服务异常: {reason}\" instead of tokens.","triggerScenarios":"Calling start_login or restore_pending_oauth_listener where a previous pending OAuth flow exists and start_callback_server_for_state cannot bind the callback_port (address already in use, permission denied) or fails while initializing the listener.","commonSituations":"Port already occupied by a previous crashed/zombie listener or another app; firewall blocking local binding; app restarted mid-login leaving a stale pending state that cannot be restored; privileged/low port configured; SELinux/security software blocking socket bind.","solutions":["Free the configured callback_port (find and kill the process listening on it, e.g. `lsof -i :PORT`).","Cancel the stale pending login and start a fresh Kiro OAuth login instead of restoring the old one.","Configure a different, unprivileged callback port (>1024) in settings.","Check firewall/antivirus policies that may prevent binding a local listener.","Retry after ensuring no duplicate app instance is running."],"exampleFix":"// before: blindly reusing the fixed callback port\nlet port = 17850;\n// after: detect a busy port before starting login\nfn port_free(p: u16) -> bool { std::net::TcpListener::bind((\"127.0.0.1\", p)).is_ok() }\nlet port = if port_free(17850) { 17850 } else { pick_free_port() };","handlingStrategy":"validation","validationCode":"// Check the callback port is bindable before restoring a pending login\nfn callback_port_free(port: u16) -> bool {\n    std::net::TcpListener::bind((\"127.0.0.1\", port)).is_ok()\n}\nif !callback_port_free(callback_port) {\n    return Err(format!(\"callback port {} occupied; free it or pick another\", callback_port));\n}","typeGuard":"fn is_callback_server_error(err: &str) -> bool {\n    err.starts_with(\"本地回调服务异常: \")\n}","tryCatchPattern":"match restore_pending_oauth_listener(&login_id, &state).await {\n    Err(err) if is_callback_server_error(&err) => {\n        cancel_pending_login(&login_id);\n        ui.prompt(\"本地回调端口被占用，请释放端口后重新登录\");\n    }\n    other => handle(other),\n}","preventionTips":["Use an unprivileged, rarely-conflicting callback port and make it configurable.","Cancel pending OAuth state cleanly instead of letting stale listeners linger.","Avoid running multiple app instances during login.","Check `lsof -i :PORT` / `netstat -ano | findstr PORT` when login hangs.","Allow loopback socket binding in firewall/AV policies."],"tags":["oauth","callback-server","port-bind","kiro"],"backgroundTag":"port-already-in-use","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}