{"record":{"id":"cc27ef086e6874c4","repo":"Stirling-Tools/Stirling-PDF","slug":"no-pricing-data-returned-cc27ef","errorCode":null,"errorMessage":"No pricing data returned","messagePattern":"No pricing data returned","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/editor/src/saas/hooks/usePlans.ts","lineNumber":85,"sourceCode":"      setError(null);\n\n      const lookupKeys = [\n        \"plan:pro\",\n        \"api:xsmall\",\n        \"api:small\",\n        \"api:medium\",\n        \"api:large\",\n      ];\n\n      const { data, error } = await supabase.functions.invoke<{\n        prices: Record<string, { unit_amount: number; currency: string }>;\n        missing: string[];\n      }>(\"stripe-price-lookup\", {\n        body: { lookup_keys: lookupKeys, currency },\n      });\n      if (error) throw error;\n      if (!data || !data.prices || !data.missing)\n        throw new Error(\"No pricing data returned\");\n      console.log(\"Fetched pricing data:\", data);\n\n      const priceMap = new Map<\n        string,\n        { unit_amount: number; currency: string }\n      >();\n      // map your UI keys to lookup keys (if names differ)\n      const keyMap: Record<string, string> = {\n        pro: \"plan:pro\",\n        xsmall: \"api:xsmall\",\n        small: \"api:small\",\n        medium: \"api:medium\",\n        large: \"api:large\",\n      };\n\n      for (const [uiKey, lookupKey] of Object.entries(keyMap)) {\n        const p = data?.prices?.[lookupKey];\n        if (p) {","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/saas/hooks/usePlans.ts#L67-L103","documentation":"Thrown by usePlans.fetchPricing() when the stripe-price-lookup Supabase edge function returns a response missing the expected shape. The code requires data, data.prices, and data.missing to all be truthy; if the edge function returns null, an empty object, or a partial response, this guard fires. The preceding `if (error) throw error` handles transport-level failures, so this specifically catches a malformed success response.","triggerScenarios":"The stripe-price-lookup edge function returns HTTP 200 but with a body that lacks the prices or missing field — e.g. returns {} on an internal error path, or returns null when no Stripe API key is configured and the function swallows the Stripe SDK error.","commonSituations":"STRIPE_SECRET_KEY not set in the edge function environment so the Stripe SDK call fails silently and the function returns an empty object; edge function deployed with a bug; lookup keys (plan:pro, api:xsmall, etc.) configured in Stripe but the function's response mapping is broken.","solutions":["Check the stripe-price-lookup edge function logs in the Supabase dashboard for Stripe SDK errors","Verify STRIPE_SECRET_KEY is set in the edge function's environment variables","Confirm the lookup keys (plan:pro, api:xsmall, api:small, api:medium, api:large) exist as active prices in Stripe","Test the edge function directly via the Supabase dashboard invoke panel with the expected body"],"exampleFix":"// before\nif (!data || !data.prices || !data.missing)\n  throw new Error(\"No pricing data returned\");\n\n// after\nif (!data || !data.prices || !data.missing) {\n  console.error(\"Pricing edge function returned malformed data:\", data);\n  throw new Error(\n    \"Pricing data unavailable. Please check edge function configuration.\",\n  );\n}","handlingStrategy":"try-catch","validationCode":"// Verify Stripe config exists before fetching pricing\nif (!import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY) {\n  console.warn('Stripe keys not configured — pricing will be unavailable');\n}","typeGuard":"function isValidPricingResponse(data: unknown): data is { prices: Record<string, { unit_amount: number; currency: string }>; missing: string[] } {\n  return (\n    typeof data === 'object' &&\n    data !== null &&\n    'prices' in data &&\n    'missing' in data &&\n    Array.isArray((data as any).missing)\n  );\n}","tryCatchPattern":"try {\n  await fetchPricing();\n} catch (e) {\n  setError(e instanceof Error ? e.message : 'Pricing unavailable');\n  // Optionally fall back to cached/static pricing\n}","preventionTips":["Verify STRIPE_SECRET_KEY is set in the stripe-price-lookup edge function environment","Confirm lookup keys (plan:pro, api:xsmall, api:small, api:medium, api:large) exist in Stripe","Test the edge function directly in the Supabase dashboard before relying on it in production","Add monitoring/alerting on the edge function for malformed responses"],"tags":["billing","stripe","edge-function","supabase","pricing","saas"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}