different-ai/openwork · error · Error
Seat checkout failed (${response.status}).
Error message
Seat checkout failed (${response.status}). What it means
Thrown by startSeatCheckout when the POST /v1/billing/stripe/checkout request (type "seat") returns a non-OK HTTP status. getRequestError first checks for a 403 reauth payload (throwing ReauthRequiredError instead) and otherwise surfaces the server's error message, falling back to this template that includes the status code. It indicates Stripe seat-subscription checkout could not be started server-side.
Source
Thrown at ee/apps/den-web/app/(den)/dashboard/_components/billing-dashboard-screen.tsx:293
};
}, [sessionHydrated, user, orgContext?.organization.id]);
async function startSeatCheckout() {
if (!canManageBillingSettings) {
setStripeError("Admins can start seat checkout from Members. Owners and super-admins manage Billing settings here.");
return;
}
setStripeError(null);
try {
await runReauthableAction("seat-checkout", async () => {
setStripeActionBusy("seat-checkout");
const { response, payload } = await requestJson(
"/v1/billing/stripe/checkout",
{ method: "POST", body: JSON.stringify({ type: "seat" }) },
12000,
);
if (!response.ok) throw getRequestError(payload, response, `Seat checkout failed (${response.status}).`);
const url = payload && typeof payload === "object" && "url" in payload && typeof payload.url === "string" ? payload.url : null;
if (!url) throw new Error("Seat checkout response did not include a URL.");
window.location.href = url;
});
} catch (error) {
setStripeError(error instanceof Error ? error.message : "Could not start seat billing checkout.");
} finally {
setStripeActionBusy(null);
}
}
async function openStripePortal() {
if (!canManageBillingSettings) {
setStripeError("Only workspace owners and super-admins can open billing portals from Settings.");
return;
}
setStripeError(null);View on GitHub (pinned to 2b7df46e8a)
Solutions
- Inspect the thrown message / response body for the server's specific error (it overrides the fallback).
- If the message is a reauth error, re-authenticate the admin session and retry (runReauthableAction handles this).
- Verify Stripe API keys and webhook config on the Den server; checkout cannot start without them.
- Confirm the org's billing state (no conflicting existing seat subscription) before retrying.
- Retry after confirming status with GET billing status; if 5xx, check server logs for Stripe API errors.
Example fix
// before
if (!response.ok) throw getRequestError(payload, response, `Seat checkout failed (${response.status}).`);
const url = isRecord(payload) && typeof payload.url === "string" ? payload.url : null;
// after
if (!response.ok) {
const err = getRequestError(payload, response, `Seat checkout failed (${response.status}).`);
console.error("seat checkout failed", response.status, payload);
throw err;
} Defensive patterns
Strategy: try-catch
Validate before calling
const canCheckout = typeof window !== "undefined" && stripeConfigured; // check org billing status via GET /v1/billing first if (!orgBillingReady) return; // avoid POST when server has no Stripe customer
Type guard
function isCheckoutUrlPayload(p: unknown): p is { url: string } {
return typeof p === "object" && p !== null && "url" in p && typeof (p as { url: unknown }).url === "string";
} Try / catch
try {
await runReauthableAction("seat-checkout", startSeatCheckout);
} catch (error) {
if (isReauthRequiredError(error)) { promptReauth(); return; }
setStripeError(error instanceof Error ? error.message : "Could not start seat billing checkout.");
} Prevention
- Check billing/org status via GET before attempting checkout
- Always wrap in runReauthableAction so 403 reauth is retried transparently
- Surface the server error message (getRequestError already does) rather than the raw fallback
- Verify Stripe env config on the server before enabling billing UI
- Treat 5xx as transient and offer a retry button
When it happens
Trigger: The den-server /v1/billing/stripe/checkout endpoint replies 4xx/5xx: org has no Stripe customer/billing record yet, Stripe not configured on the server, payment_required/seat subscription state conflicts, 401 expired session, 403 requiring reauth, or 500 from a Stripe API failure.
Common situations: Self-hosted Den server without STRIPE keys configured; admin trying to buy seats before the org has a subscription; session expired mid-action; Stripe outage or webhook misconfiguration on the host.
Related errors
- Billing portal failed (${response.status}).
- Checkout failed (${response.status}).
- Failed to update inference settings (${response.status}).
- Failed to fetch latest-mac.yml (${response.status} ${respons
- Managed MCP outbound request exceeded the guarded redirect l
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/46bf7f10240f29e6.
Report an issue: GitHub.