{"record":{"id":"f4a0a7dc2886952c","repo":"Stirling-Tools/Stirling-PDF","slug":"supabase-is-not-configured-seat-updates-are-not-a","errorCode":null,"errorMessage":"Supabase is not configured. Seat updates are not available.","messagePattern":"Supabase is not configured\\. Seat updates are not available\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/editor/src/proprietary/services/licenseService.ts","lineNumber":528,"sourceCode":"      console.error(\"Error resyncing license:\", error);\n      throw error;\n    }\n  },\n\n  /**\n   * Update enterprise seat count\n   * Creates a Stripe billing portal session for confirming seat changes\n   * @param newSeatCount - New number of seats\n   * @param licenseKey - Current license key for authentication\n   * @returns Billing portal URL for confirming the change\n   */\n  async updateEnterpriseSeats(\n    newSeatCount: number,\n    licenseKey: string,\n  ): Promise<string> {\n    // Check if Supabase is configured\n    if (!isSupabaseConfigured || !supabase) {\n      throw new Error(\n        \"Supabase is not configured. Seat updates are not available.\",\n      );\n    }\n\n    const baseUrl = window.location.origin;\n    const returnUrl = `${baseUrl}/settings/adminPlan?seats_updated=true`;\n\n    const { data, error } = await supabase.functions.invoke(\"manage-billing\", {\n      body: {\n        return_url: returnUrl,\n        license_key: licenseKey,\n        self_hosted: true,\n        new_seat_count: newSeatCount,\n      },\n    });\n\n    if (error) {\n      throw new Error(`Failed to update seat count: ${error.message}`);","sourceCodeStart":510,"sourceCodeEnd":546,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/proprietary/services/licenseService.ts#L510-L546","documentation":"Thrown by updateEnterpriseSeats when Supabase isn't configured. Enterprise seat changes are confirmed via the manage-billing Supabase edge function (with a new_seat_count body), so without Supabase the operation is unavailable. The guard fails fast with a message naming the unavailable capability (seat updates).","triggerScenarios":"Admin changes seat count in a self-hosted build without Supabase configured; isSupabaseConfigured false; calling updateEnterpriseSeats from a flavor that omits Supabase.","commonSituations":"Self-hosted deploy missing Supabase env vars; dev run without .env.local keys; the seat-management UI rendered when licensing backend is offline.","solutions":["Gate the seat-count UI on isSupabaseConfigured.","Set VITE_SUPABASE_URL/VITE_SUPABASE_ANON_KEY in the active env layer.","Catch the error and inform the user seat changes aren't available in this mode."],"exampleFix":"// before\nconst url = await licenseService.updateEnterpriseSeats(newCount, key);\n\n// after\nif (!isSupabaseConfigured) {\n  showToast(t('license.seatUpdateUnavailable'));\n  return;\n}\nconst url = await licenseService.updateEnterpriseSeats(newCount, key);","handlingStrategy":"validation","validationCode":"if (!isSupabaseConfigured) {\n  showToast(t('license.seatUpdateUnavailable'));\n  return;\n}","typeGuard":"export function canUpdateSeats(): boolean {\n  return isSupabaseConfigured;\n}","tryCatchPattern":"try {\n  await licenseService.updateEnterpriseSeats(newCount, key);\n} catch (e) {\n  if (/not configured/i.test(e instanceof Error ? e.message : \"\")) {\n    showToast(t('license.seatUpdateUnavailable'));\n  } else throw e;\n}","preventionTips":["Gate the seat-management UI on isSupabaseConfigured.","Set Supabase env vars where seat management is expected.","Hide the action in flavors that omit Supabase."],"tags":["supabase","license","enterprise","seats","billing-portal","configuration","proprietary","typescript"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}