Stirling-Tools/Stirling-PDF · error · Error
Failed to create billing portal session: ${error.message}
Error message
Failed to create billing portal session: ${error.message} What it means
Thrown by createBillingPortalSession when supabase.functions.invoke('manage-billing', ...) returns a non-null error. The manage-billing edge function creates a Stripe billing-portal session using the supplied license_key for self-hosted auth; a returned error means the function failed — invalid/expired license key, no matching Stripe customer, missing STRIPE_SECRET_KEY, or a function exception. error.message is wrapped in the thrown Error.
Source
Thrown at frontend/editor/src/proprietary/services/licenseService.ts:401
licenseKey: string,
): Promise<BillingPortalResponse> {
// Check if Supabase is configured
if (!isSupabaseConfigured || !supabase) {
throw new Error(
"Supabase is not configured. Billing portal is not available.",
);
}
const { data, error } = await supabase.functions.invoke("manage-billing", {
body: {
return_url: returnUrl,
license_key: licenseKey,
self_hosted: true, // Explicitly indicate self-hosted mode
},
});
if (error) {
throw new Error(
`Failed to create billing portal session: ${error.message}`,
);
}
return data as BillingPortalResponse;
},
/**
* Get the installation ID from the backend (MAC-based fingerprint)
*/
async getInstallationId(): Promise<string> {
try {
const response = await apiClient.get("/api/v1/admin/installation-id");
const data: InstallationIdResponse = await response.data;
return data.installationId;
} catch (error) {
console.error("Error fetching installation ID:", error);View on GitHub (pinned to 9ef20dcab8)
Solutions
- Read error.message to distinguish auth (license key) failures from Stripe errors.
- Confirm the manage-billing function is deployed with STRIPE_SECRET_KEY and that the billing portal is enabled in Stripe.
- Re-verify the license key via checkLicenseKey before opening the portal.
- Prompt the user to re-enter their license key if it's invalid.
Example fix
// before
const { url } = await licenseService.createBillingPortalSession(returnUrl, key);
// after
try {
const { url } = await licenseService.createBillingPortalSession(returnUrl, key);
window.location.href = url;
} catch (e) {
showToast(e instanceof Error ? e.message : 'Billing portal unavailable');
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!licenseKey) {
setError('License key required');
return;
}
// optionally re-verify: await licenseService.checkLicenseKey(installationId); Type guard
export function isPlausibleLicenseKey(k: string): boolean {
return typeof k === 'string' && k.trim().length > 0;
} Try / catch
try {
const { url } = await licenseService.createBillingPortalSession(returnUrl, key);
window.location.href = url;
} catch (e) {
showToast(e instanceof Error ? e.message : 'Billing portal unavailable');
if (/license|auth|invalid/i.test(e instanceof Error ? e.message : "")) promptRelicense();
} Prevention
- Enable the Stripe customer portal in the Stripe dashboard before offering this flow.
- Confirm manage-billing is deployed with STRIPE_SECRET_KEY.
- Re-verify the license key is still active before opening the portal.
When it happens
Trigger: license_key doesn't map to a Stripe customer; license was revoked/expired so the function rejects; manage-billing function missing STRIPE_SECRET_KEY secret; return_url malformed; Stripe-side error creating the portal session.
Common situations: User's license was cancelled/refunded so the Stripe customer no longer has a subscription; license key typos; edge function not deployed or missing secrets; Stripe account misconfigured for billing portal (must be enabled in Stripe dashboard).
Related errors
- Failed to fetch plans: ${error.message}
- Failed to create checkout session: ${error.message}
- Supabase is not configured. Billing portal is not available.
- Failed to update seat count: ${error.message}
- Supabase is not configured. Please use static plans instead.
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/f95cf9ad4d9bb0c8.
Report an issue: GitHub.