different-ai/openwork · error

Seat billing checkout response did not include a URL.

Error message

Seat billing checkout response did not include a URL.

What it means

After the seat-checkout API call completes, startSeatCheckout expects the response payload to contain a string url field for the checkout session redirect. If the payload is missing, not an object, or its url is absent/non-string, the provider throws "Seat billing checkout response did not include a URL." rather than redirecting to an undefined location. This indicates a malformed or failed checkout-session response from the billing endpoint.

Source

Thrown at ee/apps/den-web/app/(den)/dashboard/_providers/org-dashboard-provider.tsx:645

        ensureActiveOrganizationSelected();
        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 billing 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 billing checkout response did not include a URL.");
        }

        window.location.href = url;
      });
    } finally {
      setMutationBusy(null);
    }
  }

  async function cancelInvitation(invitationId: string) {
    if (!getCurrentAccess().canCancelInvitations) {
      throw new Error("Only workspace admins can cancel invitations.");
    }

    await runMutation("cancel-invitation", async () => {
      ensureActiveOrganizationSelected();
      const { response, payload } = await requestJson(
        `/v1/invitations/${encodeURIComponent(invitationId)}/cancel`,

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Inspect the network response of the seat-checkout request to see the actual payload shape.
  2. Retry the checkout; transient billing-provider issues can yield incomplete responses.
  3. Verify server and web app versions match the /v1 seat checkout contract (payload.url string).
  4. Report to the server team if the endpoint returns 2xx without url — the server should either return a URL or a non-2xx status.

Example fix

// before
const url = payload && typeof payload === "object" && "url" in payload && typeof payload.url === "string"
  ? payload.url : null;
if (!url) throw new Error("Seat billing checkout response did not include a URL.");

// after (server side: fail loudly instead of 2xx-without-url)
if (!checkoutSession?.url) {
  return json({ error: "checkout_session_not_created" }, { status: 502 });
}
return json({ url: checkoutSession.url });
Defensive patterns

Strategy: type-guard

Validate before calling

function hasCheckoutUrl(p: unknown): p is { url: string } {
  return typeof p === "object" && p !== null && "url" in p && typeof (p as { url: unknown }).url === "string" && (p as { url: string }).url.length > 0;
}

Type guard

function isCheckoutPayload(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 startSeatCheckout();
} catch (e) {
  if (e instanceof Error && e.message.includes("did not include a URL")) {
    showNotice("Checkout could not be started. Please retry or contact support.");
  } else throw e;
}

Prevention

When it happens

Trigger: The POST that creates the seat checkout session returns 2xx with an unexpected body — e.g. an error envelope, an empty object, or a payload shaped { checkoutUrl } instead of { url } — inside the runReauthableAction callback.

Common situations: Billing provider outage or misconfigured Stripe return path causing the server to return a success status without a session URL; API contract changed between server and web versions; a proxy/CDN stripping or rewriting the response body; reauth flow returning a different payload shape.

Related errors


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