{"record":{"id":"4a6ccbac7b974821","repo":"Stirling-Tools/Stirling-PDF","slug":"supabase-is-not-configured-billing-portal-is-not","errorCode":null,"errorMessage":"Supabase is not configured. Billing portal is not available.","messagePattern":"Supabase is not configured\\. Billing portal is not available\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/editor/src/proprietary/services/licenseService.ts","lineNumber":387,"sourceCode":"\n    if (error) {\n      throw new Error(`Failed to create checkout session: ${error.message}`);\n    }\n\n    return data as CheckoutSessionResponse;\n  },\n\n  /**\n   * Create a Stripe billing portal session for managing subscription\n   * Uses license key for self-hosted authentication\n   */\n  async createBillingPortalSession(\n    returnUrl: string,\n    licenseKey: string,\n  ): Promise<BillingPortalResponse> {\n    // Check if Supabase is configured\n    if (!isSupabaseConfigured || !supabase) {\n      throw new Error(\n        \"Supabase is not configured. Billing portal is not available.\",\n      );\n    }\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, // Explicitly indicate self-hosted mode\n      },\n    });\n\n    if (error) {\n      throw new Error(\n        `Failed to create billing portal session: ${error.message}`,\n      );\n    }\n","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/proprietary/services/licenseService.ts#L369-L405","documentation":"Thrown by createBillingPortalSession when Supabase isn't configured. The Stripe billing portal session is opened via the Supabase edge function manage-billing, so it requires the Supabase client. The guard fails fast with a message naming the unavailable capability (billing portal) so the UI can disable the 'Manage subscription' action.","triggerScenarios":"User clicks 'Manage billing' in a build without Supabase configured; isSupabaseConfigured is false; calling the method from a flavor that intentionally omits Supabase.","commonSituations":"Self-hosted deploy without Supabase env vars; dev run without .env.local Supabase keys; manage-subscription button rendered when licensing backend is offline.","solutions":["Gate the 'Manage subscription' button on isSupabaseConfigured.","Set VITE_SUPABASE_URL/VITE_SUPABASE_ANON_KEY in the active env layer.","Catch the error and inform the user billing management isn't available in this mode."],"exampleFix":"// before\nconst { url } = await licenseService.createBillingPortalSession(returnUrl, key);\n\n// after\nif (!isSupabaseConfigured) {\n  showToast(t('license.billingUnavailable'));\n  return;\n}\nconst { url } = await licenseService.createBillingPortalSession(returnUrl, key);","handlingStrategy":"validation","validationCode":"if (!isSupabaseConfigured) {\n  showToast(t('license.billingUnavailable'));\n  return;\n}","typeGuard":"export function canOpenBillingPortal(): boolean {\n  return isSupabaseConfigured;\n}","tryCatchPattern":"try {\n  await licenseService.createBillingPortalSession(returnUrl, key);\n} catch (e) {\n  if (/not configured/i.test(e instanceof Error ? e.message : \"\")) {\n    showToast(t('license.billingUnavailable'));\n  } else throw e;\n}","preventionTips":["Gate the 'Manage subscription' button on isSupabaseConfigured.","Set Supabase env vars where billing management is expected to work.","Hide the action in flavors that intentionally omit Supabase."],"tags":["supabase","stripe","billing-portal","license","configuration","proprietary","typescript"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}