TryGhost/Ghost · error · Error
Failed to continue gift subscription, please try again.
Error message
Failed to continue gift subscription, please try again.
What it means
Thrown by continueGiftCheckout() when the POST to the members 'create-stripe-checkout-session' endpoint (with continueFromGift:true) returns non-2xx. The client prefers the backend's errors[0].message and only falls back to this generic string when no structured error body is present. continueGiftCheckout upgrades a redeemed gift subscription into a recurring paid plan.
Source
Thrown at apps/portal/src/utils/api.js:607
metadata: {
checkoutType: 'upgrade',
requestSrc: 'portal',
urlHistory: getUrlHistory()
}
};
return makeRequest({
url,
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
}).then(async function (res) {
if (!res.ok) {
const errData = await res.json();
const errMssg = errData?.errors?.[0]?.message || 'Failed to continue gift subscription, please try again.';
throw new Error(errMssg);
}
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);
}
});
});
},
async checkoutGift({tierId, cadence, duration, email: customerEmail} = {}) {View on GitHub (pinned to 47d8b0e2ad)
Solutions
- Read the concrete thrown message — if it isn't the generic fallback, it carries the backend's reason (e.g. 'Tier not found').
- Confirm the currently-signed-in member is the same one who redeemed the gift (identity mismatch is common after switching accounts).
- Re-open the gift redemption flow from the original link to obtain a fresh continueFromGift context.
- Verify the destination tier/price still exists in Ghost Admin → Settings → Membership.
- Check Ghost server logs for the members stripe-checkout-session handler error.
Defensive patterns
Strategy: try-catch
Type guard
function isMembersApiErrorBody(x) {
return typeof x === 'object' && x !== null && Array.isArray(x.errors) && typeof x.errors[0]?.message === 'string';
} Try / catch
try {
await api.member.continueGiftCheckout();
} catch (err) {
showToast(err.message);
// Re-open the gift redemption link if identity/tier context is stale
} Prevention
- Continue the gift from the redemption link of the account that redeemed it.
- Keep the destination tier active in Ghost Admin.
- Treat a backend refusal as terminal for that session — re-enter via redemption.
When it happens
Trigger: A recipient who redeemed a gift subscription chooses to convert/upgrade it; the backend refuses — e.g. the gift redemption no longer maps to a valid member, the target tier is retired, Stripe customer record is missing, or the identity token doesn't match the gift recipient.
Common situations: Gift redemption link was already used or expired; the tier referenced by the gift was deleted/archived after the gift was purchased; member signed in as a different account than the one that redeemed the gift; Stripe customer was deleted in the Stripe dashboard leaving Ghost with a dangling reference.
Related errors
- Could not create Stripe checkout session
- redirectResult.error.message
- redirectResult.error.message
- We're unable to process your payment right now. Please try a
- Unable to create stripe checkout session
AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13).
Data as JSON: /api/errors/cbf3993a3c418f19.
Report an issue: GitHub.