payloadcms/payload · error · Error
Unknown error initiating payment
Error message
Unknown error initiating payment
What it means
Thrown by the catch block at the end of Stripe confirmOrder when the caught error is not an Error instance (e.g. a string, plain object, or null thrown deep in a dependency). It is the fallback branch of error instanceof Error ? error.message : 'Unknown error initiating payment'. The original error is logged via payload.logger.error before rethrowing, so the underlying cause is in the logs even though the thrown message is generic.
Source
Thrown at packages/plugin-ecommerce/src/payments/adapters/stripe/confirmOrder.ts:144
id: transaction.id,
collection: transactionsSlug,
data: {
order: order.id,
status: 'succeeded',
},
req,
})
return {
message: 'Payment initiated successfully',
orderID: order.id,
transactionID: transaction.id,
...(order.accessToken ? { accessToken: order.accessToken } : {}),
}
} catch (error) {
payload.logger.error({ err: error, msg: 'Error confirming order with Stripe' })
throw new Error(error instanceof Error ? error.message : 'Unknown error initiating payment')
}
}
View on GitHub (pinned to 00c58b35c0)
Solutions
- Check the Payload logs for the err field logged immediately before this throw to find the real cause.
- Reproduce in isolation and inspect typeof error and error.constructor.name in a debugger.
- Upgrade/downgrade the stripe package to a version whose errors are Error instances.
- Wrap third-party calls so they always reject with Error objects (e.g. catch and re-throw new Error(String(e))).
Example fix
// before: a dependency throws a non-Error
throw 'bad value' // surfaces as 'Unknown error initiating payment'
// after: normalize to Error
throw new Error('bad value') Defensive patterns
Strategy: try-catch
Validate before calling
// Wrap third-party calls so they always reject with Error instances
async function safeCall<T>(fn: () => Promise<T>): Promise<T> {
try {
return await fn()
} catch (e) {
if (e instanceof Error) throw e
throw new Error(typeof e === 'string' ? e : JSON.stringify(e))
}
} Type guard
export function isErrorLike(e: unknown): e is Error {
return e instanceof Error || (typeof e === 'object' && e !== null && typeof (e as { message?: unknown }).message === 'string')
} Try / catch
try {
await payments.confirmOrder({ data: { paymentIntentID } })
} catch (err) {
if (err instanceof Error && err.message === 'Unknown error initiating payment') {
// inspect server logs for the original err object logged just before this throw
return { ok: false, reason: 'unknown-confirm-error', checkLogs: true }
}
throw err
} Prevention
- Always read the Payload logger entry (msg 'Error confirming order with Stripe') for the real cause — the thrown message is generic by design.
- Normalize third-party rejections to Error objects before they reach the adapter.
- Pin the stripe package version known to throw Error instances.
- Add structured logging that captures error.constructor.name alongside the message.
When it happens
Trigger: Any non-Error value thrown inside confirmOrder's try block — for example a third-party SDK that throws a string, a JSON.parse on malformed metadata that throws in a wrapper, or a network layer that rejects with a plain object. Any Error-typed thrown value surfaces its own message instead; only non-Error throws reach this branch.
Common situations: Stripe SDK downgrade/upgrade introducing a non-Error rejection; a custom hook in the order-create pipeline throwing a string; JSON.parse on truncated Stripe metadata throwing a SyntaxError (that one is an Error and would surface its own message — but a wrapping library could convert it); unhandled promise rejections from misconfigured fetch polyfills.
Related errors
- Unknown error initiating payment
- Stripe secret key is required
- PaymentIntent ID is required
- No transaction found for the provided PaymentIntent ID
- Payment not completed.
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/5e90353e6e5f7acd.
Report an issue: GitHub.