{"record":{"id":"13ab655e54e1dc94","repo":"decolua/9router","slug":"windsurf-path-http-res-status-text-slice","errorCode":null,"errorMessage":"`Windsurf ${path} HTTP ${res.status}: ${text.slice(0, 200)}`","messagePattern":"`Windsurf (.+?) HTTP (.+?): (.+?)`","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/lib/oauth/providers/windsurf.js","lineNumber":20,"sourceCode":"import { extractJsonPath } from \"./_shared.js\";\n\n// ───────────────────────────────────────────────────────────────────────────\n// Windsurf OAuth helpers\n// ───────────────────────────────────────────────────────────────────────────\n\nasync function windsurfSeatRequest(baseUrl, path, body) {\n  const url = `${baseUrl.replace(/\\/$/, \"\")}${path}`;\n  const res = await fetch(url, {\n    method: \"POST\",\n    headers: {\n      Accept: \"application/json\",\n      \"Content-Type\": \"application/json\",\n      \"User-Agent\": WINDSURF_CONFIG.userAgent,\n    },\n    body: JSON.stringify(body),\n  });\n  const text = await res.text();\n  if (!res.ok) throw new Error(`Windsurf ${path} HTTP ${res.status}: ${text.slice(0, 200)}`);\n  try { return JSON.parse(text); } catch { throw new Error(`Windsurf ${path} invalid JSON`); }\n}\n\n// Parse Windsurf callback (query string or full URL): ?access_token=...&state=...\nfunction parseWindsurfCallback(raw, expectedState) {\n  const text = String(raw || \"\").trim();\n  let queryStr = text;\n  if (text.includes(\"?\")) queryStr = text.slice(text.indexOf(\"?\") + 1);\n  if (text.startsWith(\"#\")) queryStr = text.slice(1);\n  const params = Object.fromEntries(new URLSearchParams(queryStr));\n  const pick = (keys) => {\n    for (const k of keys) { const v = params[k]; if (v && String(v).trim()) return String(v).trim(); }\n    return null;\n  };\n  const err = pick([\"error\"]);\n  if (err) {\n    const desc = pick([\"error_description\"]);\n    throw new Error(desc ? `Windsurf auth failed: ${err} (${desc})` : `Windsurf auth failed: ${err}`);","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/oauth/providers/windsurf.js#L2-L38","documentation":"windsurfSeatRequest POSTs JSON to a Windsurf endpoint and throws this when the HTTP response status is not 2xx. The message embeds the endpoint path, status code, and the first 200 chars of the response body so you can see the upstream rejection reason. It is a fail-fast guard: error bodies may not be JSON, so the raw text is surfaced instead of letting JSON.parse mask it.","triggerScenarios":"Any windsurfSeatRequest call (RegisterUser, GetOneTimeAuthToken, GetCurrentUser) where Windsurf/Codeium servers return 401/403/404/429/5xx — e.g. expired or invalid firebase_id_token, wrong registerApiBaseUrl/apiServerUrl, or upstream outage.","commonSituations":"Users pasting an already-expired Firebase JWT; Windsurf changing their API host or paths; rate limiting after repeated seat checks; corporate proxy intercepting with a 403/502 page.","solutions":["Read the status and body slice in the message — 401/403 means the firebase_id_token is invalid or expired; re-run the OAuth flow to get a fresh one","Verify WINDSURF_CONFIG registerApiBaseUrl / apiServerUrl in src/lib/oauth/constants/oauth.js match Windsurf's current API host","Retry after a delay if status is 429 or 5xx (upstream throttle/outage)","Check network/proxy settings (HTTPS_PROXY) that could inject non-Windsurf error pages","Run the Windsurf OAuth flow again end-to-end rather than reusing an old pasted token"],"exampleFix":"// before: caller lets the throw propagate and the whole OAuth flow fails\nconst reg = await fetchWindsurfRegisterUser(firebaseIdToken);\n// after: surface a clear, actionable message to the dashboard user\nlet reg;\ntry { reg = await fetchWindsurfRegisterUser(firebaseIdToken); }\ncatch (e) {\n  if (/HTTP 40[13]/.test(e.message)) throw new Error('Windsurf token expired — reconnect the account');\n  throw e;\n}","handlingStrategy":"retry","validationCode":"// pre-flight: ensure a JWT-shaped firebase id token before hitting Windsurf\nconst jwtOk = (t) => typeof t === 'string' && t.trim().split('.').length === 3;\nif (!jwtOk(firebaseIdToken)) throw new Error('Refusing call: missing/malformed firebase_id_token');","typeGuard":"const isWindsurfHttpError = (e) => e instanceof Error && /^Windsurf \\S+ HTTP \\d{3}/.test(e.message);\nconst statusOf = (e) => { const m = e.message.match(/HTTP (\\d{3})/); return m ? Number(m[1]) : null; };","tryCatchPattern":"try {\n  data = await windsurfSeatRequest(baseUrl, path, body);\n} catch (e) {\n  const s = isWindsurfHttpError(e) ? statusOf(e) : null;\n  if (s === 429 || (s && s >= 500)) { await sleep(2000); data = await windsurfSeatRequest(baseUrl, path, body); }\n  else if (s === 401 || s === 403) { throw new Error('Windsurf credential rejected — re-run OAuth'); }\n  else throw e;\n}","preventionTips":["Always obtain a fresh firebase_id_token via the OAuth flow; never reuse old pasted JWTs","Treat 429/5xx as retryable with backoff; treat 401/403 as flow-restart signals","Keep WINDSURF_CONFIG base URLs/paths in sync with the current Windsurf API","Log the status + body slice for diagnostics"],"tags":["oauth","http-status","windsurf","upstream-api"],"backgroundTag":"upstream-http-error","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}