Stirling-Tools/Stirling-PDF · warning · Error

Supabase is not configured. Please use static plans instead.

Error message

Supabase is not configured. Please use static plans instead.

What it means

Thrown by licenseService.getPlans when Supabase isn't configured (isSupabaseConfigured is false or the supabase client is null). Plans/pricing are fetched live from Stripe via a Supabase edge function (stripe-price-lookup), so without Supabase the dynamic pricing path is impossible. The message explicitly points callers to the static plans fallback so the UI can still render tiers.

Source

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

const licenseService = {
  /**
   * Get available plans with pricing for the specified currency.
   *
   * Feature and highlight labels are passed in by the caller (a React hook /
   * context that resolves them via `usePlanFeatures` / `usePlanHighlights`),
   * which keeps this service free of React/i18n dependencies while still
   * returning fully localized plan content.
   */
  async getPlans(
    planFeatures: PlanFeaturesMap,
    planHighlights: PlanHighlightsMap,
    currency: string = "usd",
  ): Promise<PlansResponse> {
    try {
      // Check if Supabase is configured
      if (!isSupabaseConfigured || !supabase) {
        throw new Error(
          "Supabase is not configured. Please use static plans instead.",
        );
      }

      // Fetch all self-hosted prices from Stripe
      const { data, error } = await supabase.functions.invoke<{
        prices: Record<
          string,
          {
            unit_amount: number;
            currency: string;
            lookup_key: string;
          }
        >;
        missing: string[];
      }>("stripe-price-lookup", {
        body: {
          lookup_keys: SELF_HOSTED_LOOKUP_KEYS,

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Catch the error and fall back to the static plan definitions (the message tells you to), as the caller (usePlanFeatures/usePlanHighlights context) is expected to do.
  2. Set VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY in the active env layer if you want live Stripe pricing.
  3. Gate the dynamic-pricing UI behind isSupabaseConfigured so getPlans is only called when it can succeed.

Example fix

// before
const { plans } = await licenseService.getPlans(features, highlights);

// after
let plans;
try {
  ({ plans } = await licenseService.getPlans(features, highlights));
} catch (e) {
  if (/not configured/i.test(e.message)) plans = STATIC_PLANS;
  else throw e;
}
Defensive patterns

Strategy: validation

Validate before calling

import { isSupabaseConfigured } from "@app/services/supabaseClient";

if (!isSupabaseConfigured) {
  // use static plans; don't call getPlans
}

Type guard

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

Try / catch

try {
  return await licenseService.getPlans(features, highlights, currency);
} catch (e) {
  if (/not configured/i.test(e instanceof Error ? e.message : "")) {
    return { plans: STATIC_PLANS };
  }
  throw e;
}

Prevention

When it happens

Trigger: getPlans() called in a self-hosted build without Supabase env vars set; the supabaseClient module's isSupabaseConfigured flag is false because VITE_SUPABASE_URL/KEY are missing; calling getPlans in a build flavor that intentionally omits Supabase.

Common situations: Self-hosted deploy without the Supabase env vars configured; dev running the editor without a .env.local containing the Supabase keys; an OSS/core build that shouldn't hit licensing at all.

Related errors


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