decolua/9router · error · Error

Windsurf RegisterUser missing apiKey

Error message

Windsurf RegisterUser missing apiKey

What it means

fetchWindsurfRegisterUser POSTs the Firebase id token to Windsurf's RegisterUser endpoint and expects {apiKey, ...} (or api_key). It throws this when the response parsed fine as JSON but contains no API key under either key. The upstream accepted the request but did not return a credential — usually an upstream response-shape change or a soft business-logic rejection.

Source

Thrown at src/lib/oauth/providers/windsurf.js:55

    const desc = pick(["error_description"]);
    throw new Error(desc ? `Windsurf auth failed: ${err} (${desc})` : `Windsurf auth failed: ${err}`);
  }
  const accessToken = pick(["access_token", "token"]);
  if (!accessToken) throw new Error("Windsurf callback missing access_token");
  const state = pick(["state"]);
  if (expectedState && state && state !== expectedState) {
    throw new Error("Windsurf callback state mismatch");
  }
  return { firebaseIdToken: accessToken };
}

// POST RegisterUser {firebase_id_token} → {apiKey, apiServerUrl, name}
async function fetchWindsurfRegisterUser(firebaseIdToken) {
  const data = await windsurfSeatRequest(WINDSURF_CONFIG.registerApiBaseUrl, WINDSURF_CONFIG.registerPath, {
    firebase_id_token: firebaseIdToken,
  });
  const apiKey = extractJsonPath(data, [["apiKey"], ["api_key"]]);
  if (!apiKey) throw new Error("Windsurf RegisterUser missing apiKey");
  const apiServerUrl = extractJsonPath(data, [["apiServerUrl"], ["api_server_url"]]) || WINDSURF_CONFIG.defaultApiServerUrl;
  const name = extractJsonPath(data, [["name"]]);
  return { apiKey, apiServerUrl, name };
}

// Best-effort: GetOneTimeAuthToken → GetCurrentUser → email/name.
async function fetchWindsurfUserInfo(apiServerUrl, firebaseIdToken) {
  try {
    const authRes = await windsurfSeatRequest(apiServerUrl, WINDSURF_CONFIG.oneTimeAuthPath, { firebaseIdToken });
    const authToken = extractJsonPath(authRes, [["authToken"], ["auth_token"]]);
    if (!authToken) return { email: null, name: null };
    const userRes = await windsurfSeatRequest(apiServerUrl, WINDSURF_CONFIG.currentUserPath, {
      authToken,
      includeSubscription: true,
    });
    const user = userRes.user || userRes;
    return {
      email: extractJsonPath(user, [["email"]]),

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Log the full `data` object returned by RegisterUser to see the actual response shape
  2. Update the extractJsonPath key list in fetchWindsurfRegisterUser if Windsurf renamed/nested the field
  3. Confirm the Windsurf account has an active seat/subscription — no key is issued without one
  4. Re-run the OAuth flow to get a fresh firebase_id_token and retry
  5. Check for library updates that track the current Windsurf API

Example fix

// before
const apiKey = extractJsonPath(data, [["apiKey"], ["api_key"]]);
// after: also probe nested shapes
const apiKey = extractJsonPath(data, [["apiKey"], ["api_key"], ["data","apiKey"], ["result","apiKey"]]);
Defensive patterns

Strategy: type-guard

Validate before calling

// confirm the firebase token is JWT-shaped before RegisterUser
const jwtShaped = (t) => typeof t === 'string' && t.trim().split('.').length === 3;
if (!jwtShaped(firebaseIdToken)) throw new Error('Not a Firebase id token — run the Windsurf sign-in flow');

Type guard

const hasApiKey = (data) =>
  Boolean(data && (data.apiKey || data.api_key ||
    (data.data && data.data.apiKey) || (data.result && data.result.apiKey)));

Try / catch

const reg = await fetchWindsurfRegisterUser(fb);
if (!reg || !reg.apiKey) {
  throw new Error('Windsurf issued no apiKey — check account seat/subscription or updated response shape');
}

Prevention

When it happens

Trigger: Windsurf RegisterUser returns 200 with an error object like {success:false,...} or {message:"..."}; response wrapped differently (e.g. {data:{apiKey}}) after an API version change; account not provisioned so no key is issued.

Common situations: Windsurf changed the RegisterUser response schema; the user's account exists but has no seat so no key is minted; account region routed to an API version with different field casing.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/b9640fa45fd9bdb1. Report an issue: GitHub.