{"record":{"id":"70fdf3fde0781084","repo":"Stirling-Tools/Stirling-PDF","slug":"rpc-fn-failed","errorCode":null,"errorMessage":"RPC ${fn} failed","messagePattern":"RPC (.+?) failed","errorType":"exception","errorClass":"StripeFunctionError","httpStatus":null,"severity":"error","filePath":"frontend/editor/src/portal/billing/stripe.ts","lineNumber":102,"sourceCode":"  if (data == null) {\n    throw new StripeFunctionError(`Edge function ${name} returned no data`);\n  }\n  return data;\n}\n\n/** Call a SECURITY DEFINER public.* RPC with the admin's JWT (same client as {@link invoke}). */\nasync function rpc<T>(fn: string, args: Record<string, unknown>): Promise<T> {\n  ensureSaasSupabase();\n  const supabase = getSupabaseClient();\n  if (!supabase) {\n    throw new StripeFunctionError(\n      \"SaaS Supabase not configured — set VITE_SUPABASE_URL.\",\n      \"unconfigured\",\n    );\n  }\n  const { data, error } = await supabase.rpc(fn, args);\n  if (error) {\n    throw new StripeFunctionError(\n      error.message ?? `RPC ${fn} failed`,\n      (error as { code?: string }).code,\n    );\n  }\n  return data as T;\n}\n\n/** Inputs to {@link upsertBundleQuote} — the sized config + computed figures. */\nexport interface BundleQuoteInput {\n  teamId: number;\n  users: number;\n  posturePolicies: number;\n  sizeMult: number;\n  pipelineMult: number;\n  provisionedMonthlyVolume: number;\n  /** Size-folded run-credits = the Stripe line quantity when this quote is paid. */\n  poolCredits: number;\n  /**","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/portal/billing/stripe.ts#L84-L120","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nthrow new StripeFunctionError(\n  error.message ?? `RPC ${fn} failed`,\n  (error as { code?: string }).code,\n);\n\n// after — include hint/code for faster triage\nconst e = error as { code?: string; hint?: string };\nthrow new StripeFunctionError(\n  error.message ?? `RPC ${fn} failed (code=${e.code ?? \"?\"}${e.hint ? \": \" + e.hint : \"\"})`,\n  e.code,\n);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isPostgresError(e: unknown): e is { message?: string; code?: string; hint?: string } {\n  return typeof e === \"object\" && e !== null && (\"code\" in e || \"message\" in e);\n}","tryCatchPattern":"try {\n  await upsertBundleQuote(input);\n} catch (e) {\n  if (e instanceof StripeFunctionError) {\n    // e.code carries the PostgREST/SQL code when available\n    notifications.show({ message: `Quote failed (${e.code ?? \"unknown\"}): ${e.message}`, color: \"red\" });\n  } else throw e;\n}","preventionTips":["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."],"tags":["billing","stripe","supabase","rpc","postgres","network"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}