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.
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)
Solutions
- Capture and surface redirectResult.error.message to the user — it already comes from Stripe and is usually actionable.
- Retry checkout by clicking the button again (the .catch re-binds the click handler); if it persists, the Stripe session likely expired.
- Verify the publishable key returned by create-stripe-checkout matches the Stripe account connected in Ghost admin.
- 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
- Load Stripe.js synchronously before triggering the redirect to avoid session expiry while the script loads.
- Confirm the publishable key returned by the backend matches the connected account.
- Ask users to disable content/ad blockers if Stripe redirects silently fail.
- Re-mint the checkout session on retry rather than reusing a stale sessionId.
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
- result.error.message
- Could not create Stripe checkout session
- redirectResult.error.message
- Failed to continue gift subscription, please try again.
- Failed to process gift checkout, please try again.
AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13).
Data as JSON: /api/errors/7fad94e22366fe55.
Report an issue: GitHub.