TryGhost/Ghost · error · Error

Latest Stripe checkout session does not include a success UR

Error message

Latest Stripe checkout session does not include a success URL

What it means

Same success-URL guard as the donations/offers flows, thrown in the paid signup flow after `stripe.completeLatestSubscriptionCheckout`. After `signUpPage.fillAndSubmitPaidSignup`, the test expects the most recent Stripe checkout session to carry a `success_url` to navigate to. Absence means no subscription checkout session was recorded or its response omits the field.

Source

Thrown at e2e/helpers/playwright/flows/signup.ts:53

    const emailAddress = opts?.emailAddress ?? `test${faker.string.uuid()}@ghost.org`;
    const name = opts?.name ?? faker.person.fullName();

    await signUpPage.waitForPortalToOpen();

    if (opts?.cadence) {
        await signUpPage.switchCadence(opts.cadence);
    }

    await signUpPage.fillAndSubmitPaidSignup(emailAddress, name, opts?.tierName);

    const fakeCheckoutPage = new FakeStripeCheckoutPage(page);
    await fakeCheckoutPage.waitUntilLoaded();
    await stripe.completeLatestSubscriptionCheckout({name});

    const latestCheckoutSession = stripe.getCheckoutSessions().at(-1);
    const successUrl = latestCheckoutSession?.response.success_url;
    if (!successUrl) {
        throw new Error('Latest Stripe checkout session does not include a success URL');
    }

    await page.goto(successUrl);

    return {emailAddress, name};
}

View on GitHub (pinned to 47d8b0e2ad)

Solutions

  1. Ensure the tier named in `opts.tierName` is Stripe-synced (use the tiers sync wait flow) before paid signup.
  2. Confirm `fakeCheckoutPage.waitUntilLoaded()` resolved and `completeLatestSubscriptionCheckout` captured a session.
  3. Log `stripe.getCheckoutSessions().length` immediately before reading the success URL.
  4. Validate the cadence option is one the tier supports ('monthly'|'yearly').
Defensive patterns

Strategy: validation

Validate before calling

const sessions = stripe.getCheckoutSessions();
if (!sessions.length || !sessions.at(-1)?.response?.success_url) {
    throw new Error(`Paid signup checkout not recorded (${sessions.length} sessions)`);
}

Type guard

function isCheckoutSessionWithSuccessUrl(s: unknown): s is {response: {success_url: string}} {
    return !!s && typeof (s as any).response?.success_url === 'string';
}

Prevention

When it happens

Trigger: Paid signup flow submits the form and the fake checkout loads, but `getCheckoutSessions().at(-1)` is undefined or its `response.success_url` is missing.

Common situations: Tier/pricing not synced to Stripe before signup so no checkout session is created; cadence switch (`switchCadence`) left the signup in an invalid state; Stripe test service not capturing the subscription checkout; mock response shape regression.

Related errors


AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13). Data as JSON: /api/errors/46775ec1b1d8b7b7. Report an issue: GitHub.