{"record":{"id":"a87391a15ea63231","repo":"decolua/9router","slug":"port-56121-in-use-close-the-conflicting-process-a","errorCode":null,"errorMessage":"Port 56121 in use; close the conflicting process and retry","messagePattern":"Port 56121 in use; close the conflicting process and retry","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/shared/components/OAuthModal.js","lineNumber":349,"sourceCode":"        }\n      }\n\n      // xAI: same fixed-port server-side proxy pattern as codex (port 56121)\n      let xaiProxyActive = false;\n      let xaiServerSide = false;\n      if (provider === \"xai\") {\n        try {\n          const proxyUrl = new URL(`/api/oauth/xai/start-proxy`, window.location.origin);\n          proxyUrl.searchParams.set(\"app_port\", appPort);\n          proxyUrl.searchParams.set(\"state\", data.state);\n          proxyUrl.searchParams.set(\"code_verifier\", data.codeVerifier);\n          proxyUrl.searchParams.set(\"redirect_uri\", redirectUri);\n          const proxyRes = await fetch(proxyUrl.toString());\n          const proxyData = await proxyRes.json();\n          xaiProxyActive = proxyData.success;\n          xaiServerSide = !!proxyData.serverSide;\n          if (!xaiProxyActive && proxyData.reason === \"port_busy\") {\n            throw new Error(\"Port 56121 in use; close the conflicting process and retry\");\n          }\n        } catch (e) {\n          if (e?.message) throw e;\n          xaiProxyActive = false;\n        }\n      }\n\n      setAuthData({ ...data, redirectUri, codexServerSide, xaiServerSide });\n\n      // Guard: device_code providers return authUrl:null from /authorize. Never window.open(null)\n      // (browsers coerce it to the relative path \".../null\").\n      if (!data.authUrl) {\n        if (data.flowType === \"device_code\") {\n          throw new Error(\n            `Provider ${provider} uses device-code login but is not wired in the OAuth modal device-code list`\n          );\n        }\n        throw new Error(\"No authorization URL returned from OAuth provider\");","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/shared/components/OAuthModal.js#L331-L367","documentation":"For the xAI (Grok) flow, the modal starts a server-side callback proxy that must listen on the fixed port 56121. If /api/oauth/xai/start-proxy reports `reason: \"port_busy\"` (proxy not started) the modal throws this hard error instead of falling back, because the callback redirect_uri is hardwired to http://127.0.0.1:56121/callback.","triggerScenarios":"Starting xAI OAuth while another process is bound to TCP port 56121 — a leftover previous 9router/xAI proxy instance, another tool using that port, or a stale zombie process.","commonSituations":"A crashed previous session left the proxy running; a second dashboard instance is open; another dev service happens to occupy 56121.","solutions":["Find the process holding port 56121 (lsof -i :56121 or netstat -ano) and kill it","Retry the xAI OAuth flow after the port is free","Restart the 9Router app to clean up stale proxy processes","If a persistent conflict exists, change the conflicting service's port"],"exampleFix":"// shell check before retrying\n// before: retry while port still busy\nlsof -ti :56121 | xargs kill   // after: free the port, then retry the flow","handlingStrategy":"fallback","validationCode":"// pre-check before starting the flow (node)\nconst net = require('net');\nconst s = net.connect(56121, '127.0.0.1');\ns.once('connect', () => { console.error('port 56121 busy'); s.destroy(); });\ns.once('error', () => console.log('port 56121 free'));","typeGuard":"null","tryCatchPattern":"try {\n  await startXaiFlow();\n} catch (e) {\n  if (e.message.includes(\"Port 56121\")) {\n    // instruct: lsof -ti :56121 | xargs kill, then retry\n  }\n}","preventionTips":["Free port 56121 before starting xAI OAuth (lsof -i :56121)","Avoid running multiple dashboard instances concurrently","Restart the app after a crashed session to clean stale proxies"],"tags":["oauth","port-conflict","xai"],"backgroundTag":"port-already-in-use","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}