{"record":{"id":"1f37fa460f936f1f","repo":"Hmbown/CodeWhale","slug":"sign-in-timed-out-waiting-for-the-browser-callback","errorCode":null,"errorMessage":"{} sign-in timed out waiting for the browser callback","messagePattern":"(.+?) sign-in timed out waiting for the browser callback","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/oauth.rs","lineNumber":1373,"sourceCode":"        pkce,\n        redirect_uri,\n        authorize_url,\n    })\n}\n\nconst CALLBACK_TIMEOUT: Duration = Duration::from_secs(300);\nconst CALLBACK_HTML_OK: &str = \"<!doctype html><html><body><p>Signed in to Codewhale. You can close this tab.</p></body></html>\";\nconst CALLBACK_HTML_ERR: &str = \"<!doctype html><html><body><p>Sign-in did not complete. You can close this tab and retry in Codewhale.</p></body></html>\";\n\nfn wait_for_callback(\n    listeners: &[TcpListener],\n    params: &OAuthProviderParams,\n    expected_state: &str,\n) -> Result<String> {\n    let deadline = Instant::now() + CALLBACK_TIMEOUT;\n    loop {\n        if Instant::now() >= deadline {\n            bail!(\n                \"{} sign-in timed out waiting for the browser callback\",\n                params.display_name\n            );\n        }\n        // Whichever stack `localhost` resolved to for the browser is the one\n        // that gets the connection; poll them all.\n        for listener in listeners {\n            match listener.accept() {\n                Ok((stream, _)) => {\n                    return handle_callback_stream(stream, params, expected_state);\n                }\n                Err(error)\n                    if error.kind() == std::io::ErrorKind::WouldBlock\n                        || error.kind() == std::io::ErrorKind::Interrupted => {}\n                Err(error) => {\n                    return Err(error).context(format!(\n                        \"{} OAuth callback accept failed\",\n                        params.display_name","sourceCodeStart":1355,"sourceCodeEnd":1391,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/oauth.rs#L1355-L1391","documentation":"The local loopback HTTP listener waited `CALLBACK_TIMEOUT` for the browser to complete sign-in and call back with the OAuth code, and the deadline expired. The library polls all resolved localhost stacks for the redirect; if none arrives in time the login is abandoned with this error.","triggerScenarios":"`pkce_login`'s callback wait loop reaches `Instant::now() >= deadline` before any callback request is received — the browser never opened, the user never finished sign-in, or the redirect went to the wrong port/loopback family.","commonSituations":"Browser failed to launch in a headless/SSH environment; user walked away and didn't complete sign-in; popup blocker swallowed the tab; the authorize URL's redirect port was blocked by another process or firewall; slow provider login page exceeded the timeout.","solutions":["Re-run the sign-in and complete the browser flow before the timeout.","Open the printed authorize URL manually in a local browser if none launched (e.g. over SSH, use port forwarding).","Verify nothing else occupies the loopback callback port and that a firewall/proxy isn't blocking `localhost` callbacks."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match pkce_login(provider).await {\n    Err(e) if e.to_string().contains(\"timed out waiting for the browser callback\") => {\n        // retry once, or instruct user to open the printed URL manually\n    }\n    other => other,\n}","preventionTips":["Ensure a graphical browser is available (no headless/SSH without port forwarding).","Complete sign-in soon after the browser opens; the wait window is bounded.","Confirm the loopback callback port is free and not firewalled."],"tags":["oauth","timeout","loopback-callback"],"backgroundTag":"request-timeout","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}