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

  1. Inspect the thrown message / response body for the server's specific error (it overrides the fallback).
  2. If the message is a reauth error, re-authenticate the admin session and retry (runReauthableAction handles this).
  3. Verify Stripe API keys and webhook config on the Den server; checkout cannot start without them.
  4. Confirm the org's billing state (no conflicting existing seat subscription) before retrying.
  5. 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

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


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/46bf7f10240f29e6. Report an issue: GitHub.