TryGhost/Ghost · error · Error
Unable to create stripe checkout session
Error message
Unable to create stripe checkout session
What it means
Thrown by editBilling() when the POST to members 'create-stripe-update-session' returns non-2xx. This endpoint builds a Stripe Checkout Session for updating the card on an existing subscription. Unlike other handlers, this throw discards the backend error body entirely — it always uses the generic message regardless of what the backend returned.
Source
Thrown at apps/portal/src/utils/api.js:758
const checkoutCancelUrl = window.location.href.startsWith(siteUrlObj.href) ? new URL(window.location.href) : new URL(siteUrl);
checkoutCancelUrl.searchParams.set('stripe', 'billing-update-cancel');
cancelUrl = checkoutCancelUrl.href;
}
return makeRequest({
url,
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
identity: identity,
subscription_id: subscriptionId,
successUrl,
cancelUrl
})
}).then(function (res) {
if (!res.ok) {
throw new Error('Unable to create stripe checkout session');
}
return res.json();
}).then(function (result) {
const stripe = window.Stripe(result.publicKey);
return stripe.redirectToCheckout({
sessionId: result.sessionId
});
}).then(function (result) {
if (result.error) {
throw new Error(result.error.message);
}
}).catch(function (err) {
throw err;
});
},
async manageBilling({returnUrl, subscriptionId} = {}) {
const identity = await api.member.identity();View on GitHub (pinned to 47d8b0e2ad)
Solutions
- Check the Ghost server log for the create-stripe-update-session handler error — the backend reason is logged but not surfaced here.
- Confirm subscriptionId is a valid, active Stripe subscription belonging to the signed-in member.
- Re-authenticate the member (refresh identity) before retrying.
- Verify the Stripe subscription still exists in the Stripe dashboard (not deleted).
- Patch editBilling() to surface the backend's res.json() error body instead of the generic string (improves diagnosability).
Example fix
// before: backend error body discarded
if (!res.ok) {
throw new Error('Unable to create stripe checkout session');
}
// after: surface the backend reason like checkoutPlan does
if (!res.ok) {
const errData = await res.json().catch(() => null);
const err = errData?.errors?.[0] || {};
throw new Error(err.message || 'Unable to create stripe checkout session');
} Defensive patterns
Strategy: try-catch
Validate before calling
// Validate the subscription context before calling
function canEditBilling(identity, subscriptionId) {
return Boolean(identity && subscriptionId && typeof subscriptionId === 'string');
} Try / catch
try {
await api.member.editBilling({subscriptionId});
} catch (err) {
// Generic message — check Ghost server logs for the real reason
showToast(err.message);
} Prevention
- Pass a valid, active subscriptionId that belongs to the signed-in member.
- Patch editBilling to surface the backend res.json() error body (the generic string hides detail).
- Don't offer billing edit on complimentary (non-Stripe) subscriptions.
When it happens
Trigger: Member clicks 'Edit billing details' to update their card; the backend can't create the update session — subscriptionId is missing or not found, the subscription belongs to a different member, Stripe customer/subscription was deleted in the Stripe dashboard, or the member's identity token doesn't authorize that subscription.
Common situations: subscriptionId passed is empty/stale; the subscription was cancelled in Stripe but still listed in Ghost; identity token expired; Stripe Connect key rotated so session creation fails server-side; member trying to edit billing on a complimentary (non-Stripe) subscription.
Related errors
- Unable to create Stripe billing portal session
- Failed to continue gift subscription, please try again.
- We're unable to process your payment right now. Please try a
- result.error.message
- Failed to update newsletter
AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13).
Data as JSON: /api/errors/5d16e5f43e5f67c4.
Report an issue: GitHub.