Stirling-Tools/Stirling-PDF · error · StripeFunctionError
payg_upsert_bundle_quote returned no row
Error message
payg_upsert_bundle_quote returned no row
What it means
Thrown by upsertBundleQuote when the payg_upsert_bundle_quote RPC resolves without error but returns zero rows. The helper indexes rows?.[0] and treats an empty result set as a contract failure — the function is expected to return exactly one quote row.
Source
Thrown at frontend/editor/src/portal/billing/stripe.ts:173
input: BundleQuoteInput,
): Promise<BundleQuote> {
const rows = await rpc<BundleQuoteRow[]>("payg_upsert_bundle_quote", {
p_team_id: input.teamId,
p_posture_policies: input.posturePolicies,
p_size_mult: input.sizeMult,
p_pipeline_mult: input.pipelineMult,
p_pool_credits: input.poolCredits,
p_users: input.users,
p_provisioned_monthly_volume: input.provisionedMonthlyVolume,
p_price_minor: input.priceMinor,
p_currency: input.currency,
p_consented: input.consented,
p_eula_version: input.eulaVersion,
...(input.quoteId != null ? { p_quote_id: input.quoteId } : {}),
});
const row = rows?.[0];
if (!row) {
throw new StripeFunctionError("payg_upsert_bundle_quote returned no row");
}
return {
quoteId: row.quote_id,
status: row.status,
validUntil: row.valid_until,
};
}
/** A team's latest open bundle quote — {@code payg_get_latest_bundle_quote} result, for resume. */
export interface LatestBundleQuote {
quoteId: number;
users: number | null;
posturePolicies: number;
sizeMult: number;
pipelineMult: number;
poolCredits: number;
priceMinor: number | null;
currency: string | null;View on GitHub (pinned to 9ef20dcab8)
Solutions
- Inspect the SQL function payg_upsert_bundle_quote — find branches that return no row and make them raise a meaningful exception instead.
- Validate inputs before calling (teamId > 0, non-empty currency, priceMinor >= 0, consented flag).
- Check the team exists and the caller's JWT has access to it (RLS/SECURITY DEFINER grant).
- Re-run the RPC in the Supabase SQL editor with the same args to see the empty result and adjust.
Example fix
// SQL function — before INSERT INTO payg_bundle_quote (...) VALUES (...) RETURNING *; -- on conflict or guard, returns nothing // after — raise instead of silently returning empty IF p_users <= 0 THEN RAISE EXCEPTION 'invalid user count: %', p_users; END IF; INSERT ... RETURNING *;
Defensive patterns
Strategy: validation
Validate before calling
function isValidQuoteInput(i: BundleQuoteInput): boolean {
return (
i.teamId > 0 &&
i.users > 0 &&
typeof i.currency === "string" && i.currency.length === 3 &&
Number.isFinite(i.priceMinor) && i.priceMinor >= 0
);
}
if (!isValidQuoteInput(input)) {
throw new Error("Invalid quote input — refusing to call payg_upsert_bundle_quote.");
}
await upsertBundleQuote(input); Type guard
function isQuoteRow(row: unknown): row is { quote_id: number; status: string; valid_until: string } {
return typeof row === "object" && row !== null &&
typeof (row as any).quote_id === "number";
} Try / catch
try {
await upsertBundleQuote(input);
} catch (e) {
if (e instanceof StripeFunctionError && /returned no row/i.test(e.message)) {
notifications.show({ message: "Quote could not be created. Check team and pricing.", color: "red" });
} else throw e;
} Prevention
- Validate BundleQuoteInput fully before calling (users>0, currency ISO, priceMinor>=0).
- Ensure the SQL function raises a clear exception rather than returning empty on bad input.
- Run the RPC in the Supabase SQL editor with sample args during dev to confirm a row is returned.
When it happens
Trigger: The SQL function payg_upsert_bundle_quote returns no row — e.g. an input validation inside the function rejected the payload (returning nothing instead of raising), a conflict path that returns empty, or a RETURNING clause that matched nothing.
Common situations: Passing an invalid team_id, a currency/price the function rejects, or a consented/EULA-version combination the function gates on; a DB-level constraint that silently short-circuits; the function was redeployed with a bug in its RETURNING.
Related errors
- RPC ${fn} failed
- create-payg-bundle-quote failed
- accept-payg-bundle-quote failed
- Edge function ${name} returned no data
- create-checkout-session failed
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/da379da52a16b07e.
Report an issue: GitHub.