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
Thrown by the shared helper `getLatestCheckoutSuccessUrl` used in upgrade flows. It reads `stripe.getCheckoutSessions().at(-1)?.response.success_url` and throws if absent, centralizing the same check duplicated across donations/offers/signup flows. Failure means no upgrade checkout session was recorded or its response omits `success_url`.
Source
Thrown at e2e/helpers/playwright/flows/upgrade.ts:11
import {FakeStripeCheckoutPage, HomePage, PortalAccountPage, PortalAccountPlanPage} from '@/helpers/pages';
import {signInAsMember} from './sign-in';
import type {Member} from '@/data-factory';
import type {Page} from '@playwright/test';
import type {StripeTestService} from '@/helpers/services/stripe';
function getLatestCheckoutSuccessUrl(stripe: StripeTestService): string {
const successUrl = stripe.getCheckoutSessions().at(-1)?.response.success_url;
if (!successUrl) {
throw new Error('Latest Stripe checkout session does not include a success URL');
}
return successUrl;
}
export async function completePaidUpgradeViaPortal(page: Page, stripe: StripeTestService, member: Member, opts: {
cadence: 'monthly' | 'yearly';
tierName: string;
}): Promise<void> {
await signInAsMember(page, member);
const homePage = new HomePage(page);
await homePage.openAccountPortal();
const portalAccountPage = new PortalAccountPage(page);
await portalAccountPage.waitForPortalToOpen();
await portalAccountPage.openPlanSelection();
View on GitHub (pinned to 47d8b0e2ad)
Solutions
- Confirm the member is genuinely changing plans/cadence so a checkout session is created.
- Verify `completeLatestSubscriptionCheckout` ran after the portal plan change was submitted.
- Inspect `stripe.getCheckoutSessions()` length and the last session's shape before the helper is called.
- Ensure the target tier is Stripe-synced before attempting the upgrade.
Defensive patterns
Strategy: validation
Validate before calling
const sessions = stripe.getCheckoutSessions();
if (!sessions.length || !sessions.at(-1)?.response?.success_url) {
throw new Error(`Upgrade 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
- Ensure the member is genuinely changing plan/cadence so a checkout is created.
- Sync the target tier to Stripe before the upgrade.
- Prefer the shared `getLatestCheckoutSuccessUrl` helper over re-implementing the check.
When it happens
Trigger: The paid-upgrade-via-portal flow completes checkout (`completeLatestSubscriptionCheckout`), but the recorded sessions array is empty or the last session lacks `success_url`.
Common situations: Member upgrade did not actually create a new Stripe checkout (e.g., already on the target plan); Stripe test service did not capture the upgrade checkout; portal plan-change flow navigated away before checkout creation; mock response shape change.
Related errors
- Latest Stripe checkout session does not include a success UR
- Latest Stripe checkout session does not include a success UR
- Invalid donation amount: ${value}
- Latest Stripe checkout session does not include a success UR
- Expected redeemed offer member ${emailAddress} to have a sub
AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13).
Data as JSON: /api/errors/f186f0a57b6e4de8.
Report an issue: GitHub.