{"record":{"id":"5c81b6b82b757054","repo":"Stirling-Tools/Stirling-PDF","slug":"errordata-error-failed-to-synchronize-user-upgr","errorCode":null,"errorMessage":"errorData.error || Failed to synchronize user upgrade","messagePattern":"errorData\\.error \\|\\| Failed to synchronize user upgrade","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/editor/src/saas/services/userService.ts","lineNumber":41,"sourceCode":"  const formData = new URLSearchParams();\n  if (authMethod) {\n    formData.append(\"authMethod\", authMethod);\n  }\n\n  const response = await fetch(`${API_BASE}/user-role/promptToAuthUser`, {\n    method: \"POST\",\n    headers: {\n      \"Content-Type\": \"application/x-www-form-urlencoded\",\n    },\n    credentials: \"include\", // Include cookies for authentication\n    body: formData.toString(),\n  });\n\n  if (!response.ok) {\n    const errorData = await response\n      .json()\n      .catch(() => ({ error: \"Failed to synchronize user upgrade\" }));\n    throw new Error(errorData.error || \"Failed to synchronize user upgrade\");\n  }\n\n  return response.json();\n};\n","sourceCodeStart":23,"sourceCodeEnd":46,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/saas/services/userService.ts#L23-L46","documentation":"Thrown by synchronizeUserUpgrade() when the POST /api/v1/user-role/promptToAuthUser backend endpoint returns a non-OK HTTP status. The function attempts to parse errorData.error from the JSON body, falling back to a generic message if parsing fails. This endpoint upgrades an anonymous user to an authenticated user in the backend's security context — the backend derives the user from the session cookie, not the request body.","triggerScenarios":"The backend session cookie has expired between the Supabase auth upgrade and this sync call; the backend security context cannot resolve the user from the cookie; the backend throws during the upgrade (e.g., user already upgraded, database error); the backend is down or returns 5xx.","commonSituations":"Session cookie expired (credentials:'include' sends cookies but they may be stale); backend restarted and lost session state; user's anonymous session in the backend doesn't match the newly authenticated Supabase identity; CORS preflight failure blocking the POST.","solutions":["Read errorData.error for the backend's specific error message","Verify the session cookie is still valid — re-authenticate via Supabase and retry","Check backend logs for /user-role/promptToAuthUser exceptions","Ensure credentials:'include' is actually sending the cookie (check CORS Allow-Credentials header on the backend)","Retry the sync after confirming the backend is healthy"],"exampleFix":"// before\nif (!response.ok) {\n  const errorData = await response.json().catch(() => ({ error: \"Failed to synchronize user upgrade\" }));\n  throw new Error(errorData.error || \"Failed to synchronize user upgrade\");\n}\n\n// after\nif (!response.ok) {\n  const errorData = await response.json().catch(() => ({ error: \"Failed to synchronize user upgrade\" }));\n  if (response.status === 401 || response.status === 403) {\n    // Session expired — re-auth and retry once\n    await refreshSession();\n    return synchronizeUserUpgrade(authMethod);\n  }\n  throw new Error(errorData.error || \"Failed to synchronize user upgrade\");\n}","handlingStrategy":"retry","validationCode":"// Verify session is valid before syncing\nconst { data: { session } } = await supabase.auth.getSession();\nif (!session?.access_token) {\n  await refreshSession();\n  return;\n}","typeGuard":null,"tryCatchPattern":"try {\n  await synchronizeUserUpgrade(authMethod);\n} catch (e) {\n  if (e instanceof Error && (e.message.includes('401') || e.message.includes('403'))) {\n    // Session expired — re-authenticate and retry once\n    await refreshSession();\n    await synchronizeUserUpgrade(authMethod);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Verify the session cookie is still valid (credentials:'include') before calling the sync endpoint","Ensure the backend CORS policy includes Allow-Credentials so cookies are actually sent","Call synchronizeUserUpgrade immediately after Supabase auth confirms the upgrade, before the session can expire","Handle 401/403 by re-authenticating and retrying rather than showing a hard error"],"tags":["auth","user-upgrade","backend","session","saas"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}