{"record":{"id":"6b2264a2352bcdc9","repo":"mihomo-party-org/clash-party","slug":"login-timed-out","errorCode":null,"errorMessage":"Login timed out","messagePattern":"Login timed out","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/main/resolve/plugin/oauth.ts","lineNumber":51,"sourceCode":"  const open = opts.open ?? ((u: string): Promise<void> => shell.openExternal(u))\n  const timeoutMs = opts.timeoutMs ?? CALLBACK_TIMEOUT_MS\n\n  const p = new Promise<OAuthResult>((resolve, reject) => {\n    const server = http.createServer()\n    let settled = false\n    const finish = (fn: () => void): void => {\n      if (settled) return\n      settled = true\n      clearTimeout(timer)\n      server.close()\n      fn()\n    }\n    const timer = setTimeout(() => finish(() => reject(new Error('Login timed out'))), timeoutMs)\n\n    server.on('request', (req, res) => {\n      const reqUrl = new URL(req.url ?? '/', 'http://127.0.0.1')\n      if (reqUrl.pathname !== '/callback') {\n        res.writeHead(404)\n        res.end()\n        return\n      }\n      const code = reqUrl.searchParams.get('code')\n      const retState = reqUrl.searchParams.get('state')\n      res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' })\n      if (!code || retState !== state) {\n        res.end('<html><body>Login failed. You may close this window.</body></html>')\n        finish(() => reject(new Error('Invalid OAuth callback (state mismatch or missing code)')))\n        return\n      }\n      res.end('<html><body>Login complete. You may close this window.</body></html>')\n      const addr = server.address()\n      const port = typeof addr === 'object' && addr ? addr.port : 0\n      finish(() => resolve({ code, verifier, redirectUri: `http://127.0.0.1:${port}/callback` }))\n    })\n    server.on('error', (e) => finish(() => reject(e)))\n    server.listen(0, '127.0.0.1', () => {","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/mihomo-party-org/clash-party/blob/911e090537acdf7c50bee1c3aebecc2ef119a8b5/src/main/resolve/plugin/oauth.ts#L33-L69","documentation":"browserLogin starts a local HTTP server and opens a browser for an OAuth authorization-code flow; a setTimeout rejects the promise with 'Login timed out' when the callback with the authorization code does not arrive within timeoutMs. This aborts the pending login so the app does not wait forever on a server that may never receive a redirect.","triggerScenarios":"The user closes the browser window/tab before completing login; the browser never opens (headless/SSH environment, no default browser configured); the OAuth provider page errors or the user abandons the flow; network blocking redirects back to http://127.0.0.1:<port>/callback within the timeout.","commonSituations":"Running the app on a remote machine without a GUI; corporate proxy/firewall blocking the loopback callback; user multi-tasking and letting the login page sit until it expires; very short timeoutMs configuration.","solutions":["Retry the login (call the login command again) and complete the flow promptly in the opened browser window.","Ensure a default browser is available/openable in the environment, or copy the auth URL and open it manually on another machine — make sure the redirect goes to the same host running the app.","Increase the timeout value if flows routinely need longer.","Check firewall/proxy rules so 127.0.0.1 callback requests are not blocked."],"exampleFix":"// before\nawait oauth() // user misses the window, rejects after timeoutMs\n// after\ntry {\n  await oauth()\n} catch (e) {\n  if (e.message === 'Login timed out') {\n    notifyUser('Login window expired — click Login to try again')\n    await oauth()\n  } else throw e\n}","handlingStrategy":"try-catch","validationCode":"// Before starting OAuth, check the environment can complete the flow:\nif (!process.defaultApp && (process.platform === 'linux' && !process.env.DISPLAY)) {\n  console.warn('No GUI available — open the printed auth URL manually on a machine that can reach this host')\n}","typeGuard":null,"tryCatchPattern":"try {\n  await browserLogin()\n} catch (e) {\n  if (e instanceof Error && e.message === 'Login timed out') {\n    // prompt user to retry; optionally increase timeoutMs and re-invoke\n    await retryWithBackoff(() => browserLogin(), { retries: 2 })\n  } else {\n    throw e\n  }\n}","preventionTips":["Complete the OAuth flow promptly once the browser window opens.","Increase timeoutMs if the flow legitimately needs more time.","Ensure a default browser is configured and 127.0.0.1 callback traffic is not blocked by firewall/proxy.","On headless machines, use SSH port forwarding or copy the auth URL to a browser that can reach the callback host."],"tags":["oauth","timeout","network"],"backgroundTag":"oauth-callback-timeout","analyzedSha":"911e090537acdf7c50bee1c3aebecc2ef119a8b5","analyzedAt":"2026-08-30T13:00:49.174Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}