TryGhost/Ghost · error · Error
We're unable to process your payment right now. Please try a
Error message
We're unable to process your payment right now. Please try again later.
What it means
Thrown by checkoutDonation() when the create-stripe-checkout-session POST (type:'donation') returns non-2xx with no structured errors[0] to rethrow. Donations are one-time payments, so this fires when the backend rejects the donation session creation and provides no parseable error detail.
Source
Thrown at apps/portal/src/utils/api.js:723
const response = await makeRequest({
url,
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
});
const responseJson = await response.json();
if (!response.ok) {
const error = responseJson?.errors?.[0];
if (error) {
throw error;
}
throw new Error('We\'re unable to process your payment right now. Please try again later.');
}
return responseJson;
},
async editBilling({successUrl, cancelUrl, subscriptionId} = {}) {
const siteUrlObj = new URL(siteUrl);
const identity = await api.member.identity();
const url = endpointFor({type: 'members', resource: 'create-stripe-update-session'});
if (!successUrl) {
const checkoutSuccessUrl = new URL(siteUrl);
checkoutSuccessUrl.searchParams.set('stripe', 'billing-update-success');
successUrl = checkoutSuccessUrl.href;
}
if (!cancelUrl) {
const checkoutCancelUrl = window.location.href.startsWith(siteUrlObj.href) ? new URL(window.location.href) : new URL(siteUrl);
checkoutCancelUrl.searchParams.set('stripe', 'billing-update-cancel');View on GitHub (pinned to 47d8b0e2ad)
Solutions
- Confirm donations are enabled in Ghost Admin → Settings → Membership and a donation tier exists.
- Inspect the raw response in devtools — status + body — to see whether it's a Ghost 4xx or a proxy HTML page.
- Verify the Stripe Connect account supports one-time payments and is fully linked.
- Check that Portal and Ghost backend versions are compatible for the donation flow.
- If response.json() throws (HTML body), fix the proxy routing so the request reaches Ghost's JSON API.
Example fix
// before: response.json() throws on non-JSON before this fallback can fire
const responseJson = await response.json();
if (!response.ok) { ... throw new Error('We\'re unable...'); }
// after: parse defensively like checkoutGift does, then fall back
let responseJson = {};
try { responseJson = await response.json(); } catch { /* HTML page */ }
if (!response.ok) {
const error = responseJson?.errors?.[0];
if (error) throw error;
throw new Error(`We're unable to process your payment right now (HTTP ${response.status}).`);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Confirm donations are configured before offering the flow
// (check the site config / Portal capabilities, not the raw API)
function donationsEnabled(siteConfig) {
return Boolean(siteConfig?.donations?.enabled && siteConfig?.donations?.tier);
} Type guard
function hasStructuredError(body) {
return body && Array.isArray(body.errors) && body.errors[0];
} Try / catch
try {
await api.member.checkoutDonation({...});
} catch (err) {
showToast(err.message);
// If response.json() threw upstream (non-JSON), err is a SyntaxError — fix the proxy path.
} Prevention
- Enable donations and a donation tier in Ghost Admin before exposing the flow.
- Ensure Stripe Connect supports one-time payments.
- Patch checkoutDonation to parse the body defensively (try/catch around response.json()).
When it happens
Trigger: Donations not enabled on the site but the Portal offered the flow; the donation tier is retired; Stripe Connect account misconfigured for one-time payments; amount/currency invalid; or a proxy interposed an HTML error page (checkoutDonation calls response.json() directly without the defensive try/catch that checkoutGift has, so a non-JSON body would throw a SyntaxError before reaching this branch).
Common situations: Ghost version where the donations feature flag is off but the theme/Portal bundle is newer; Stripe account not configured to accept one-time payments (only subscriptions); currency mismatch between Portal and Stripe; response.json() throwing on an HTML proxy error (which surfaces as a different error but leaves this one as the documented fallback).
Related errors
- Failed to continue gift subscription, please try again.
- Unable to create stripe checkout session
- Unable to create Stripe billing portal session
- Failed to update newsletter
- Failed to update member
AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13).
Data as JSON: /api/errors/0dbb029bf564351d.
Report an issue: GitHub.