Stirling-Tools/Stirling-PDF · error · StripeFunctionError
Edge function ${name} returned no data
Error message
Edge function ${name} returned no data What it means
Thrown by invoke() when supabase.functions.invoke resolves without error but returns a null/undefined body. The helper treats a missing payload as a contract violation because every billing edge function is expected to return data.
Source
Thrown at frontend/editor/src/portal/billing/stripe.ts:85
name: string,
body: Record<string, unknown>,
): Promise<T> {
ensureSaasSupabase();
const supabase = getSupabaseClient();
if (!supabase) {
throw new StripeFunctionError(
"SaaS Supabase not configured — set VITE_SUPABASE_URL.",
"unconfigured",
);
}
const { data, error } = await supabase.functions.invoke<T>(name, { body });
if (error) {
throw new StripeFunctionError(
error.message ?? `Edge function ${name} failed`,
);
}
if (data == null) {
throw new StripeFunctionError(`Edge function ${name} returned no data`);
}
return data;
}
/** Call a SECURITY DEFINER public.* RPC with the admin's JWT (same client as {@link invoke}). */
async function rpc<T>(fn: string, args: Record<string, unknown>): Promise<T> {
ensureSaasSupabase();
const supabase = getSupabaseClient();
if (!supabase) {
throw new StripeFunctionError(
"SaaS Supabase not configured — set VITE_SUPABASE_URL.",
"unconfigured",
);
}
const { data, error } = await supabase.rpc(fn, args);
if (error) {
throw new StripeFunctionError(
error.message ?? `RPC ${fn} failed`,View on GitHub (pinned to 9ef20dcab8)
Solutions
- Check the named edge function source — confirm every code path returns Response.json(...) with a non-null body.
- Redeploy the function after fixing the empty-return branch.
- Confirm the Supabase project + function slug in VITE_SUPABASE_URL point at the correct deployment.
- Add server-side logging in the function so empty returns are traceable.
Example fix
// edge function (Supabase) — before
return new Response(null, { status: 200 });
// after
return new Response(JSON.stringify({ success: true, ...result }), {
headers: { "Content-Type": "application/json" },
}); Defensive patterns
Strategy: try-catch
Type guard
function hasPayload<T>(data: T | null | undefined): data is T {
return data != null;
} Try / catch
try {
const res = await invoke<CheckoutResponse>("create-checkout-session", body);
// invoke already throws on null data, so reaching here means data is present
useCheckout(res);
} catch (e) {
if (e instanceof StripeFunctionError) toast(e.message);
} Prevention
- Ensure every edge function code path returns Response.json with a non-null body.
- Add a post-deploy smoke test that calls each function and asserts a non-empty body.
- Log empty-body responses server-side so they are caught before users hit them.
When it happens
Trigger: An edge function returns HTTP 200 with an empty body, returns null explicitly, or responds with a 204 No Content. Because invoke was typed to return T, null data means the typed contract was broken.
Common situations: An edge function deploy that forgot to return Response.json(...); a function that returns early on an unhandled branch; a proxy/gateway stripping the body; a successful function whose return was refactored to return null.
Related errors
- create-checkout-session failed
- create-checkout-session returned neither client_secret nor U
- create-payg-bundle-quote failed
- accept-payg-bundle-quote failed
- finalize-payg-bundle-invoice failed
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/98cd00b53d901904.
Report an issue: GitHub.