Stirling-Tools/Stirling-PDF · error · Error
Edge function returned no client_secret
Error message
Edge function returned no client_secret
What it means
Thrown in StripeCheckoutPanel.tsx as a component-level defensive guard after createCheckoutSession() returns. If the session object has no url (hosted fallback) and no clientSecret, the checkout cannot proceed. This is typically unreachable because billing.ts createCheckoutSession() already throws this same error — but if the billing seam is shadowed by a platform override (desktop/cloud) that returns an unexpected shape, this guard catches it. The error is caught by the component's own try/catch and surfaced as setError(msg).
Source
Thrown at frontend/editor/src/cloud/components/shared/config/configSections/StripeCheckoutPanel.tsx:199
// return URL (browser origin on web, deep link on desktop).
const session = await createCheckoutSession({
teamId,
currency,
// Maps to Stripe's customer_email when the team has no Stripe
// customer yet — prefills + locks the email field in Checkout. Teams
// with an existing customer get the email locked from the customer
// record instead; this field is ignored for them.
billingOwnerEmail: billingEmail,
});
if (cancelled) return;
// Hosted-url fallback: no embedded iframe, hand the URL to the system
// browser. The deep-link / origin return URL brings the user back.
if (session.url && !session.clientSecret) {
await openExternal(session.url);
return;
}
if (!session.clientSecret) {
throw new Error("Edge function returned no client_secret");
}
setClientSecret(session.clientSecret);
setIsMock(
Boolean(session.mock) || session.clientSecret.startsWith("cs_mock_"),
);
} catch (e: unknown) {
if (cancelled) return;
const msg =
e instanceof Error
? e.message
: tRef.current(
"payg.checkout.error.startFailed",
"Couldn't start checkout session",
);
setError(msg);
onErrorRef.current?.(msg);
} finally {
if (!cancelled) setLoading(false);View on GitHub (pinned to 9ef20dcab8)
Solutions
- If using a platform override of createCheckoutSession, ensure it always returns either { clientSecret, mock } or { url }
- Verify the @app/* billing seam resolves to the correct implementation for the current build flavor
- Check the create-checkout-session edge function logs if the real billing.ts implementation is in use
- Ensure STRIPE_SECRET_KEY is configured in the edge function
Example fix
// before
if (!session.clientSecret) {
throw new Error("Edge function returned no client_secret");
}
// after
if (!session.clientSecret) {
throw new Error(
session.url
? "Checkout returned only a URL but the hosted path was already handled"
: "Edge function returned no client_secret",
);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Verify teamId is valid before checkout
if (!teamId) {
setError('A team is required to start checkout');
return;
} Type guard
function isUsableSession(session: CheckoutSession | null): session is { clientSecret: string; mock?: boolean } {
return session !== null && typeof session.clientSecret === 'string' && session.clientSecret.length > 0;
} Try / catch
// The component already catches at line 205:
// catch (e: unknown) {
// if (cancelled) return;
// const msg = e instanceof Error ? e.message : t('payg.checkout.error.startFailed');
// setError(msg);
// onErrorRef.current?.(msg);
// } Prevention
- If shadowing createCheckoutSession in a platform layer, ensure it always returns clientSecret or url
- Verify the @app/* billing seam resolves to the correct implementation for the current build flavor
- Check STRIPE_SECRET_KEY and edge function configuration if using the real billing.ts implementation
- Test the checkout flow in each build flavor (core, saas, desktop) to catch seam resolution issues
When it happens
Trigger: A platform-specific override of createCheckoutSession (via @app/* shadow in desktop or cloud layer) returns an object with neither url nor clientSecret. Or the billing seam's return type is widened/changed and the component receives an empty object.
Common situations: Desktop or cloud build shadows createCheckoutSession with a stub that returns {}; billing service contract changed but the platform override wasn't updated; the edge function returns a response that the seam maps to an empty CheckoutSession.
Related errors
- Edge function returned no client_secret
- unconfigured
- create-checkout-session failed
- create-checkout-session returned neither client_secret nor U
- No pricing data returned
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/c0f5d6a4df024103.
Report an issue: GitHub.