{"record":{"id":"2577fd891dfc8732","repo":"Stirling-Tools/Stirling-PDF","slug":"edge-function-returned-no-client-secret","errorCode":null,"errorMessage":"Edge function returned no client_secret","messagePattern":"Edge function returned no client_secret","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/editor/src/saas/services/billing.ts","lineNumber":60,"sourceCode":"      ...(params.billingOwnerEmail\n        ? { billing_owner_email: params.billingOwnerEmail }\n        : {}),\n    },\n  });\n\n  if (error) {\n    throw error;\n  }\n  if (data?.client_secret) {\n    return {\n      clientSecret: data.client_secret,\n      mock: Boolean(data.mock) || data.client_secret.startsWith(\"cs_mock_\"),\n    };\n  }\n  if (data?.url) {\n    return { url: data.url };\n  }\n  throw new Error(\"Edge function returned no client_secret\");\n}\n\n/**\n * The Stripe publishable key for embedded checkout. On the web this is the\n * build-time {@code VITE_STRIPE_PUBLISHABLE_KEY}.\n */\nexport function getStripePublishableKey(): string {\n  return import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY ?? \"\";\n}\n\n/**\n * Mint a Stripe Customer Portal session via the PAYG\n * {@code create-customer-portal-session} edge function (its RPC enforces team\n * membership). return_url is the current location so Stripe brings the user\n * back to this page on close.\n */\nexport async function createPortalSession(\n  params: PortalParams,","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/saas/services/billing.ts#L42-L78","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the create-checkout-session edge function logs in the Supabase dashboard","Verify STRIPE_SECRET_KEY is set in the edge function's environment variables","Confirm the team_id is valid and the current user is a member of that team","Verify the currency and price configuration in Stripe match what the edge function expects"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Verify team has a valid ID before checkout\nif (!params.teamId) {\n  throw new Error('A valid team is required to start checkout');\n}","typeGuard":"function hasCheckoutSecret(data: unknown): data is { client_secret: string; mock?: boolean } {\n  return (\n    typeof data === 'object' &&\n    data !== null &&\n    typeof (data as any).client_secret === 'string'\n  );\n}","tryCatchPattern":"try {\n  const session = await createCheckoutSession({ teamId, currency });\n  if (session.clientSecret) {\n    setClientSecret(session.clientSecret);\n  } else if (session.url) {\n    openExternal(session.url);\n  }\n} catch (e) {\n  const msg = e instanceof Error ? e.message : 'Checkout failed to start';\n  setError(msg);\n}","preventionTips":["Verify STRIPE_SECRET_KEY is set in the create-checkout-session edge function environment","Confirm the team_id is valid and the user is a member before initiating checkout","Test the edge function end-to-end with a known-good team_id in the Supabase dashboard","Monitor the edge function for Stripe API errors that produce incomplete responses"],"tags":["billing","stripe","edge-function","checkout","supabase","saas"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}