Stirling-Tools/Stirling-PDF · error · Error

Edge function returned no client_secret

Error message

Edge function returned no client_secret

What it means

Thrown by createCheckoutSession() in billing.ts when the create-checkout-session Supabase edge function returns data that has neither a client_secret nor a url. The function checks client_secret first, then url (hosted fallback), and only throws if both are absent. This indicates the edge function returned a success response with an incomplete payload.

Source

Thrown at frontend/editor/src/saas/services/billing.ts:60

      ...(params.billingOwnerEmail
        ? { billing_owner_email: params.billingOwnerEmail }
        : {}),
    },
  });

  if (error) {
    throw error;
  }
  if (data?.client_secret) {
    return {
      clientSecret: data.client_secret,
      mock: Boolean(data.mock) || data.client_secret.startsWith("cs_mock_"),
    };
  }
  if (data?.url) {
    return { url: data.url };
  }
  throw new Error("Edge function returned no client_secret");
}

/**
 * The Stripe publishable key for embedded checkout. On the web this is the
 * build-time {@code VITE_STRIPE_PUBLISHABLE_KEY}.
 */
export function getStripePublishableKey(): string {
  return import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY ?? "";
}

/**
 * Mint a Stripe Customer Portal session via the PAYG
 * {@code create-customer-portal-session} edge function (its RPC enforces team
 * membership). return_url is the current location so Stripe brings the user
 * back to this page on close.
 */
export async function createPortalSession(
  params: PortalParams,

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Check the create-checkout-session edge function logs in the Supabase dashboard
  2. Verify STRIPE_SECRET_KEY is set in the edge function's environment variables
  3. Confirm the team_id is valid and the current user is a member of that team
  4. Verify the currency and price configuration in Stripe match what the edge function expects
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify team has a valid ID before checkout
if (!params.teamId) {
  throw new Error('A valid team is required to start checkout');
}

Type guard

function hasCheckoutSecret(data: unknown): data is { client_secret: string; mock?: boolean } {
  return (
    typeof data === 'object' &&
    data !== null &&
    typeof (data as any).client_secret === 'string'
  );
}

Try / catch

try {
  const session = await createCheckoutSession({ teamId, currency });
  if (session.clientSecret) {
    setClientSecret(session.clientSecret);
  } else if (session.url) {
    openExternal(session.url);
  }
} catch (e) {
  const msg = e instanceof Error ? e.message : 'Checkout failed to start';
  setError(msg);
}

Prevention

When it happens

Trigger: The edge function partially succeeds — it receives the request but fails to create a Stripe Checkout Session, returning an object without client_secret or url. This happens when STRIPE_SECRET_KEY is missing (Stripe SDK throws and the function swallows it), the team_id is invalid, or the Stripe API returns an error that the function wraps without populating the expected fields.

Common situations: STRIPE_SECRET_KEY not configured in the edge function environment; team_id doesn't correspond to a valid team; Stripe API error (invalid currency, missing price) swallowed by the edge function; edge function deployed in test/mock mode returning an empty object.

Related errors


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