different-ai/openwork · error · Error

Checkout response did not include a URL.

Error message

Checkout response did not include a URL.

What it means

startSubscribeCheckout POSTs to create a Stripe checkout session and expects a JSON payload containing a string `url` field to redirect the browser to. If the response is ok but has no string `url`, this error is thrown because the redirect cannot proceed.

Source

Thrown at ee/apps/den-web/app/(den)/dashboard/_components/inference-screen.tsx:363

      setError("Only workspace admins can start OpenWork Models checkout.");
      return;
    }

    setError(null);
    try {
      await runReauthableAction("inference-checkout", async () => {
        setSubscribeBusy(true);
        const { response, payload } = await requestJson(
          "/v1/billing/stripe/checkout",
          { method: "POST", body: JSON.stringify({ type: "inference" }) },
          12000,
        );
        if (!response.ok) {
          throw getRequestError(payload, response, `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("Checkout response did not include a URL.");
        }
        window.location.href = url;
      });
    } catch (checkoutError) {
      setError(checkoutError instanceof Error ? checkoutError.message : "Could not start checkout.");
      setSubscribeBusy(false);
    }
  }

  async function toggleEnabled() {
    if (!canManageModels) {
      setError("Only workspace admins can manage OpenWork Models.");
      return;
    }
    if (!status) return;
    if (status.enabled || !status.subscribed) {
      router.push(getBillingRoute(activeOrg?.slug));
      return;

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Verify Stripe environment variables (secret key, price ID) are configured on the Den server.
  2. Inspect the raw checkout endpoint response to see what shape it actually returns.
  3. Upgrade server and dashboard to matching versions so the response includes `url`.
  4. Check server logs for Stripe API errors during session creation.

Example fix

// before
const url = payload && typeof payload === "object" && "url" in payload && typeof payload.url === "string" ? payload.url : null;
if (!url) throw new Error("Checkout response did not include a URL.");
// after
const url = isRecord(payload) && typeof payload.url === "string" && payload.url.startsWith("https://") ? payload.url : null;
if (!url) throw new Error(`Checkout response did not include a URL. Payload: ${JSON.stringify(payload).slice(0, 200)}`);
Defensive patterns

Strategy: type-guard

Validate before calling

const data = await res.json();
if (!(data && typeof data === "object" && typeof (data as { url?: unknown }).url === "string")) {
  throw new Error("Checkout response did not include a URL.");
}

Type guard

function hasCheckoutUrl(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 startSubscribeCheckout();
} catch (e) {
  setError(e instanceof Error ? e.message : "Could not start checkout.");
  setSubscribeBusy(false);
}

Prevention

When it happens

Trigger: The checkout-session endpoint returns 200 with a body lacking `url` (e.g. {"sessionId":...} instead), a null url because Stripe session creation silently failed, or a non-JSON body.

Common situations: Billing/Stripe not configured on the server (no price ID or webhook secret), API shape changed after a server upgrade, or the org's billing state prevents session creation but the endpoint still returns 200.

Related errors


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