TryGhost/Ghost · error · Error

redirectResult.error.message

Error message

redirectResult.error.message

What it means

Thrown in apps/portal/src/data-attributes.js after Stripe.js redirectToCheckout returns a result with a populated error field. The error uses the Stripe-provided message verbatim (not localized) and is caught by the .catch handler that shows it in the error element next to the checkout button.

Solutions

  1. Capture and surface redirectResult.error.message to the user — it already comes from Stripe and is usually actionable.
  2. Retry checkout by clicking the button again (the .catch re-binds the click handler); if it persists, the Stripe session likely expired.
  3. Verify the publishable key returned by create-stripe-checkout matches the Stripe account connected in Ghost admin.
  4. Ask the user to disable content/ad blockers for the site if redirects silently fail.

Example fix

// before
if (redirectResult.error) {
    throw new Error(redirectResult.error.message);
}

// after: keep the message but tag it so the UI can localize the wrapper
if (redirectResult.error) {
    const e = new Error(redirectResult.error.message);
    e.code = 'stripe_redirect_failed';
    throw e;
}
Defensive patterns

Strategy: try-catch

Type guard

function isStripeRedirectError(result) {
    return result?.error != null && typeof result.error.message === 'string';
}

Try / catch

try {
    const r = await stripe.redirectToCheckout({sessionId});
    if (isStripeRedirectError(r)) { throw new Error(r.error.message); }
} catch (err) {
    showError(el, err.message);
    el.classList.remove('loading');
    el.addEventListener('click', clickHandler);
}

Prevention

When it happens

Trigger: create-stripe-checkout succeeded and returned a sessionId/publicKey; window.Stripe(publicKey).redirectToCheckout({sessionId}) rejects or resolves with {error:{message}} — typical when the session expired, the key mismatches, or Stripe.js cannot redirect (popup blocked, third-party cookies disabled).

Common situations: User took too long between clicking checkout and Stripe loading (session expired on Stripe's side); Stripe publishable key mismatched the secret key used to create the session; Safari ITP blocking third-party cookies for the Stripe redirect; ad-blockers interfering with js.stripe.com.

Related errors


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

Appendix: source

Thrown at apps/portal/src/data-attributes.js:193

                cancelUrl: checkoutCancelUrl,
                metadata
            })
        }).then(function (res) {
            if (!res.ok) {
                throw new Error(t('Could not create Stripe checkout session'));
            }
            return res.json();
        });
    }).then(function (responseBody) {
        if (responseBody.url) {
            return window.location.assign(responseBody.url);
        }
        const stripe = window.Stripe(responseBody.publicKey);
        return stripe.redirectToCheckout({
            sessionId: responseBody.sessionId
        }).then(function (redirectResult) {
            if (redirectResult.error) {
                throw new Error(redirectResult.error.message);
            }
        });
    }).catch(function (err) {
        console.error(err);
        el.addEventListener('click', clickHandler);
        el.classList.remove('loading');
        if (errorEl) {
            errorEl.innerText = err.message;
        }
        el.classList.add('error');
    });
}

export function handleDataAttributes({siteUrl, site = {}, member, offers = [], doAction, captureException} = {}) {
    if (!siteUrl) {
        return;
    }

View on GitHub (pinned to 47d8b0e2ad)