{"record":{"id":"74ec22317c12746a","repo":"decolua/9router","slug":"authdata-error","errorCode":null,"errorMessage":"authData.error","messagePattern":"authData\\.error","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/shared/components/OAuthModal.js","lineNumber":195,"sourceCode":"    setError(\"Authorization timeout\");\n    setStep(\"error\");\n    setPolling(false);\n  }, [provider, onSuccess]);\n\n  // Trae/Windsurf proxy OAuth flow: dynamic-port local callback → auto exchange.\n  const startProxyFlow = useCallback(async (providerId) => {\n    // 1. Start the local callback server (returns a dynamic port + callback URL).\n    const startRes = await fetch(`/api/oauth/${providerId}/start-proxy`);\n    const startData = await startRes.json();\n    if (!startRes.ok || !startData.success || !startData.callbackUrl) {\n      throw new Error(startData.reason || startData.error || `Failed to start ${providerId} callback server`);\n    }\n    // 2. Build the authorize URL with redirect_uri = proxy callback URL.\n    const authorizeUrl = new URL(`/api/oauth/${providerId}/authorize`, window.location.origin);\n    authorizeUrl.searchParams.set(\"redirect_uri\", startData.callbackUrl);\n    const authRes = await fetch(authorizeUrl);\n    const authData = await authRes.json();\n    if (!authRes.ok) throw new Error(authData.error);\n    // 3. Register the session so the proxy can match the incoming callback.\n    //    Zed also passes code_verifier (encodes the RSA private key for decrypt);\n    //    sent via POST body so the private key never lands in URL/query logs.\n    const regBody = { state: authData.state };\n    if (authData.codeVerifier) regBody.codeVerifier = authData.codeVerifier;\n    await fetch(`/api/oauth/${providerId}/register-session`, {\n      method: \"POST\",\n      headers: { \"Content-Type\": \"application/json\" },\n      body: JSON.stringify(regBody),\n    });\n    // 4. Open popup; proxy auto-exchanges on callback, modal polls poll-status.\n    setAuthData({ ...authData, proxyProvider: providerId });\n    setStep(\"waiting\");\n    popupRef.current = window.open(authData.authUrl, \"oauth_popup\", \"width=600,height=700\");\n    if (!popupRef.current) setStep(\"input\"); // popup blocked → fall back to manual paste\n  }, []);\n\n  // Start OAuth flow","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/shared/components/OAuthModal.js#L177-L213","documentation":"In startProxyFlow, after fetching `/api/oauth/{providerId}/authorize` (which builds the upstream authorize URL for the Trae/Windsurf/Zed proxy flow), the modal throws when the HTTP response status is not ok, surfacing the server-provided `error` string. This means the server-side authorize step failed before any popup was opened. The message shown to the user is whatever the API returned in its JSON body.","triggerScenarios":"GET /api/oauth/{trae|windsurf|zed}/authorize?redirect_uri=... returns a non-2xx status — e.g. provider credentials missing server-side, upstream authorize-URL construction failing, or the start-proxy callback URL being invalid.","commonSituations":"Provider OAuth client credentials not configured in the gateway; upstream provider (Trae/Windsurf/Zed) returning an error while generating the authorize URL; misconfigured redirect_uri because start-proxy failed silently; network/proxy issues between the gateway and the upstream IdP.","solutions":["Read the exact `error` string from the response body to identify the server-side cause","Verify the provider's OAuth client credentials are configured in the gateway settings","Re-run the flow; if start-proxy failed, check `startData.success`/`reason` from /start-proxy first","Check gateway logs for the upstream request that produced the error"],"exampleFix":"// before\nconst authRes = await fetch(authorizeUrl);\nconst authData = await authRes.json();\nif (!authRes.ok) throw new Error(authData.error);\n// after\nconst authRes = await fetch(authorizeUrl);\nconst authData = await authRes.json();\nif (!authRes.ok) throw new Error(authData.error || authData.reason || `Authorize failed (${authRes.status})`);","handlingStrategy":"try-catch","validationCode":"const r = await fetch(authorizeUrl);\nif (!r.ok) console.error(\"authorize failed:\", (await r.json()).error);","typeGuard":"null","tryCatchPattern":"try {\n  const res = await fetch(authorizeUrl);\n  const data = await res.json();\n  if (!res.ok) throw new Error(data.error || `Authorize failed (${res.status})`);\n} catch (e) {\n  setError(e.message); // show retry guidance\n}","preventionTips":["Ensure provider OAuth credentials are configured before opening the modal","Check gateway logs for the failing upstream authorize call","Handle non-JSON responses defensively (res.json() can throw)"],"tags":["oauth","network","http-error"],"backgroundTag":"oauth-authorize-request-failed","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}