{"record":{"id":"072298efca41cb9b","repo":"Significant-Gravitas/AutoGPT","slug":"server-returned-status","errorCode":null,"errorMessage":"Server returned ${status}.","messagePattern":"Server returned (.+?)\\.","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"autogpt_platform/frontend/src/app/(platform)/settings/billing/components/AutomationCreditsTab/BalanceCard/useBalanceCard.ts","lineNumber":61,"sourceCode":"      const result = await requestTopUp({\n        data: { credit_amount: Math.round(numericAmount * 100) },\n      });\n      const status = (result as { status?: number } | undefined)?.status;\n      const body = result?.data as\n        | { checkout_url?: string; detail?: string | { msg?: string } }\n        | undefined;\n\n      if (status && status >= 400) {\n        // Surface backend error detail (FastAPI conventionally returns\n        // ``{\"detail\": \"...\"}``) instead of the generic \"no URL\" message —\n        // the actual failure is almost always a Stripe-side error\n        // (stale customer ID, missing product, invalid API key) that the\n        // user / their team needs to see to fix.\n        const detail =\n          typeof body?.detail === \"string\"\n            ? body.detail\n            : (body?.detail?.msg ?? `Server returned ${status}.`);\n        throw new Error(detail);\n      }\n\n      const url = body?.checkout_url;\n      if (url) {\n        // Navigating away — don't touch React state on the unmounting tree.\n        window.location.href = url;\n        return;\n      }\n\n      throw new Error(\n        \"Stripe didn't return a checkout URL. Check backend logs for the underlying Stripe error.\",\n      );\n    } catch (error) {\n      toast({\n        title: \"Couldn't start checkout\",\n        description:\n          error instanceof Error\n            ? error.message","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/Significant-Gravitas/AutoGPT/blob/9c8bb5550f446ba5d3046b78896578742495b3cf/autogpt_platform/frontend/src/app/(platform)/settings/billing/components/AutomationCreditsTab/BalanceCard/useBalanceCard.ts#L43-L79","documentation":"Thrown by the billing BalanceCard's top-up flow when the checkout-session request returns status >= 400 and the body's detail is neither a string nor an object with a msg field. The code deliberately prefers FastAPI's {detail: ...} (string or {msg}) so users see the real Stripe-side failure; 'Server returned ${status}.' with the embedded code is the last resort when the body shape is unrecognized.","triggerScenarios":"POST to create the Stripe checkout session failing with a non-FastAPI body: an HTML error page from a proxy, an empty body, or a JSON error in a different shape — combined with 4xx/5xx statuses caused by stale Stripe customer IDs, missing STRIPE_SECRET_KEY/product config, or amount validation failures.","commonSituations":"Self-hosted deployments with unset/misconfigured Stripe keys; Stripe test-mode keys paired with a live-mode customer (or vice versa); deleted Stripe products/prices still referenced by backend config; gateway timeouts returning HTML.","solutions":["Check the backend logs — the comment in code says it outright: the real cause is almost always Stripe-side and needs backend visibility.","Verify Stripe configuration on the backend: STRIPE_SECRET_KEY, the product/price IDs for credit top-up, and webhook setup.","Confirm the user's Stripe customer ID isn't stale (deleted customer in the Stripe dashboard) — backend re-creates or updates it if config is right.","Match test/live mode: frontend, backend keys, and existing customer records must all be in the same mode."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"function hasFastApiDetail(body: unknown): body is { detail: string | { msg: string } } {\n  return (\n    typeof body === \"object\" && body !== null && \"detail\" in body &&\n    (typeof (body as any).detail === \"string\" ||\n     typeof (body as any).detail?.msg === \"string\")\n  );\n}","typeGuard":"function isCheckoutHttpError(err: unknown): boolean {\n  return err instanceof Error && /^Server returned \\d+\\.$/.test(err.message);\n}","tryCatchPattern":"try {\n  await startCheckout(amount);\n} catch (error) {\n  // message already prefers body.detail / detail.msg — show it verbatim\n  toast({ title: \"Couldn't start checkout\", description: (error as Error).message, variant: \"destructive\" });\n}","preventionTips":["Always surface FastAPI detail on >=400 (as this code does) — never swap in a friendlier generic message for billing errors.","Verify Stripe env config in a smoke test at deploy time so misconfig is caught before users hit checkout.","Test test-mode vs live-mode consistency across frontend, backend keys, and stored customer IDs."],"tags":["billing","stripe","checkout","http-status","config"],"backgroundTag":null,"analyzedSha":"9c8bb5550f446ba5d3046b78896578742495b3cf","analyzedAt":"2026-08-14T17:17:21.957Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}