Stirling-Tools/Stirling-PDF · error · Error

Supabase is not configured. Billing portal is not available.

Error message

Supabase is not configured. Billing portal is not available.

What it means

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.

Source

Thrown at frontend/editor/src/proprietary/services/licenseService.ts:387

    if (error) {
      throw new Error(`Failed to create checkout session: ${error.message}`);
    }

    return data as CheckoutSessionResponse;
  },

  /**
   * Create a Stripe billing portal session for managing subscription
   * Uses license key for self-hosted authentication
   */
  async createBillingPortalSession(
    returnUrl: string,
    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}`,
      );
    }

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Gate the 'Manage subscription' button on isSupabaseConfigured.
  2. Set VITE_SUPABASE_URL/VITE_SUPABASE_ANON_KEY in the active env layer.
  3. Catch the error and inform the user billing management isn't available in this mode.

Example fix

// before
const { url } = await licenseService.createBillingPortalSession(returnUrl, key);

// after
if (!isSupabaseConfigured) {
  showToast(t('license.billingUnavailable'));
  return;
}
const { url } = await licenseService.createBillingPortalSession(returnUrl, key);
Defensive patterns

Strategy: validation

Validate before calling

if (!isSupabaseConfigured) {
  showToast(t('license.billingUnavailable'));
  return;
}

Type guard

export function canOpenBillingPortal(): boolean {
  return isSupabaseConfigured;
}

Try / catch

try {
  await licenseService.createBillingPortalSession(returnUrl, key);
} catch (e) {
  if (/not configured/i.test(e instanceof Error ? e.message : "")) {
    showToast(t('license.billingUnavailable'));
  } else throw e;
}

Prevention

When it happens

Trigger: User clicks 'Manage billing' in a build without Supabase configured; isSupabaseConfigured is false; calling the method from a flavor that intentionally omits Supabase.

Common situations: Self-hosted deploy without Supabase env vars; dev run without .env.local Supabase keys; manage-subscription button rendered when licensing backend is offline.

Related errors


AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13). Data as JSON: /api/errors/4a6ccbac7b974821. Report an issue: GitHub.