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
- Log the full `data` object returned by RegisterUser to see the actual response shape
- Update the extractJsonPath key list in fetchWindsurfRegisterUser if Windsurf renamed/nested the field
- Confirm the Windsurf account has an active seat/subscription — no key is issued without one
- Re-run the OAuth flow to get a fresh firebase_id_token and retry
- 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
- Log the full RegisterUser JSON when onboarding fails — schema drift is the usual cause
- Keep extractJsonPath key lists updated with any new field casing/nesting
- Verify the account has an active Windsurf seat before automating onboarding
- Monitor library updates that track Windsurf API changes
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
- Runway: no task id returned
- Zed callback must include user_id and access_token
- access_token is required
- refresh_token is required
- client_id is required
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/b9640fa45fd9bdb1.
Report an issue: GitHub.