Stirling-Tools/Stirling-PDF · error · StripeFunctionError
RPC ${fn} failed
Error message
RPC ${fn} failed What it means
Fallback message in rpc() when a PostgREST/supabase.rpc call rejects with an error that has no .message. The helper still forwards the error's code when present (the cast `(error as { code?: string }).code`), but the human text falls back to naming the failed function.
Source
Thrown at frontend/editor/src/portal/billing/stripe.ts:102
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`,
(error as { code?: string }).code,
);
}
return data as T;
}
/** Inputs to {@link upsertBundleQuote} — the sized config + computed figures. */
export interface BundleQuoteInput {
teamId: number;
users: number;
posturePolicies: number;
sizeMult: number;
pipelineMult: number;
provisionedMonthlyVolume: number;
/** Size-folded run-credits = the Stripe line quantity when this quote is paid. */
poolCredits: number;
/**View on GitHub (pinned to 9ef20dcab8)
Solutions
- Read the PostgREST error code/hint from the StripeFunctionError.code field and the underlying error in dev tools.
- Check the SQL function for the named fn in the database — look at EXCEPTION blocks and the SECURITY DEFINER grant.
- Validate the RPC args (team_id, quote_id, etc.) before calling rpc().
- Keep @supabase/supabase-js on the version the code expects to avoid error-shape drift.
Example fix
// before
throw new StripeFunctionError(
error.message ?? `RPC ${fn} failed`,
(error as { code?: string }).code,
);
// after — include hint/code for faster triage
const e = error as { code?: string; hint?: string };
throw new StripeFunctionError(
error.message ?? `RPC ${fn} failed (code=${e.code ?? "?"}${e.hint ? ": " + e.hint : ""})`,
e.code,
); Defensive patterns
Strategy: try-catch
Type guard
function isPostgresError(e: unknown): e is { message?: string; code?: string; hint?: string } {
return typeof e === "object" && e !== null && ("code" in e || "message" in e);
} Try / catch
try {
await upsertBundleQuote(input);
} catch (e) {
if (e instanceof StripeFunctionError) {
// e.code carries the PostgREST/SQL code when available
notifications.show({ message: `Quote failed (${e.code ?? "unknown"}): ${e.message}`, color: "red" });
} else throw e;
} Prevention
- Validate RPC args (teamId > 0, currency, priceMinor) before calling rpc().
- Pin @supabase/supabase-js to avoid PostgREST error-shape changes.
- Surface e.code in toasts so SQL-side failures are diagnosable.
When it happens
Trigger: supabase.rpc(fn, args) rejects with an error object lacking message (or message === ''), e.g. a PostgREST error with only a code/hint, or a transport error surfaced without text.
Common situations: A SECURITY DEFINER function raised an exception with a code but no message; a PostgREST-level error (4xx on the RPC) whose shape changed across supabase-js versions; a network failure mid-RPC.
Related errors
- payg_upsert_bundle_quote returned no row
- Edge function ${name} failed
- quote PDF fetch failed
- unconfigured
- Edge function ${name} returned no data
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/70fdf3fde0781084.
Report an issue: GitHub.