{"record":{"id":"78403f0f28bd51e9","repo":"zed-industries/zed","slug":"unexpected-path-in-oauth-callback","errorCode":null,"errorMessage":"unexpected path in OAuth callback: {}","messagePattern":"unexpected path in OAuth callback: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/oauth_callback_server/src/oauth_callback_server.rs","lineNumber":358,"sourceCode":"                }\n\n                let _ = tx.send(result);\n                return;\n            }\n        });\n\n        Ok((redirect_uri, rx))\n    }\n\n    fn handle_oauth_callback_request(\n        request: &tiny_http::Request,\n        expected_path: &str,\n    ) -> Result<OAuthCallbackParams> {\n        let url = Url::parse(&format!(\"http://localhost{}\", request.url()))\n            .context(\"malformed callback request URL\")?;\n\n        if url.path() != expected_path {\n            anyhow::bail!(\"unexpected path in OAuth callback: {}\", url.path());\n        }\n\n        let query = url\n            .query()\n            .ok_or_else(|| anyhow!(\"OAuth callback has no query string\"))?;\n        OAuthCallbackParams::parse_query(query)\n    }\n\n    /// Callback path reserved for evicting a previously-running OAuth callback\n    /// server bound to the same port. Always handled, regardless of `config.path`.\n    const CANCEL_PATH: &str = \"/cancel\";\n\n    const BIND_MAX_ATTEMPTS: u32 = 10;\n    const BIND_RETRY_DELAY: Duration = Duration::from_millis(200);\n    const CANCEL_REQUEST_TIMEOUT: Duration = Duration::from_secs(2);\n\n    fn bind_callback_server(config: &OAuthCallbackServerConfig) -> Result<tiny_http::Server> {\n        // Ephemeral ports always succeed; skip the cancel-retry dance entirely.","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/zed-industries/zed/blob/f4178619acd0d47ea1f76a2025c42962c6d6638c/crates/oauth_callback_server/src/oauth_callback_server.rs#L340-L376","documentation":"The tiny_http callback server binds a loopback port and accepts only requests whose URL path equals the unique expected callback path. Url::parse succeeds but any other path bails with the actual path seen. A dedicated /cancel path and 404s for random scanners are handled separately; this error is for paths that parsed but did not match.","triggerScenarios":"Something other than the provider redirect hits the callback port: a browser prefetch/probe of localhost, an antivirus or local agent scanning ports, a stale browser tab replaying an old callback URL from a previous sign-in attempt (whose path differed), or a second concurrent flow targeting the same port.","commonSituations":"Browser history/autocomplete firing an old OAuth callback URL; localhost port-scanning tools; retrying an old authorization link after the server restarted with a new path.","solutions":["Retry the sign-in from the app — each flow generates a fresh path/port","Close stale browser tabs or history autocomplete entries pointing at old localhost callback URLs","If a local scanner/AV probes loopback ports, exclude the callback port range or disable the probe during sign-in"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fn path_matches(expected: &str, request_url: &str) -> bool {\n    Url::parse(&format!(\"http://localhost{request_url}\"))\n        .map(|u| u.path() == expected)\n        .unwrap_or(false)\n}","typeGuard":"fn is_expected_callback_path(url: &Url, expected: &str) -> bool {\n    url.path() == expected\n}","tryCatchPattern":"match handle_oauth_callback_request(&request, expected_path) {\n    Err(e) if e.to_string().contains(\"unexpected path\") => {\n        respond_404(); // ignore probes/stale tabs; keep server alive for the real callback\n    }\n    r => r?,\n}","preventionTips":["Only ever open authorize URLs freshly generated for the current server instance","Don't bookmark or replay localhost OAuth callback URLs","Ignore/log-and-continue unmatched paths instead of tearing down the flow","If local security tools scan loopback ports, expect occasional stray requests and tolerate them"],"tags":["oauth","callback-server","url","localhost"],"backgroundTag":"oauth-callback-url-mismatch","analyzedSha":"f4178619acd0d47ea1f76a2025c42962c6d6638c","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}