payloadcms/payload · error · Error

A valid amount is required to initiate a payment.

Error message

A valid amount is required to initiate a payment.

What it means

Thrown by Stripe initiatePayment when amount (cart.subtotal) is falsy, not a number, or <= 0. Stripe requires a positive integer amount in the smallest currency unit. The adapter derives amount = cart.subtotal at the top of the function, so a cart without a numeric subtotal, or with subtotal 0, triggers this guard before any Stripe call.

Source

Thrown at packages/plugin-ecommerce/src/payments/adapters/stripe/initiatePayment.ts:42

    if (!secretKey) {
      throw new Error('Stripe secret key is required.')
    }

    if (!currency) {
      throw new Error('Currency is required.')
    }

    if (!cart || !cart.items || cart.items.length === 0) {
      throw new Error('Cart is empty or not provided.')
    }

    if (!customerEmail || typeof customerEmail !== 'string') {
      throw new Error('A valid customer email is required to make a purchase.')
    }

    if (!amount || typeof amount !== 'number' || amount <= 0) {
      throw new Error('A valid amount is required to initiate a payment.')
    }

    const stripe = new Stripe(secretKey, {
      // API version can only be the latest, stripe recommends ts ignoring it
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore - ignoring since possible versions are not type safe, only the latest version is recognised
      apiVersion: apiVersion || '2025-06-30.preview',
      appInfo: appInfo || {
        name: 'Stripe Payload Plugin',
        url: 'https://payloadcms.com',
      },
    })

    try {
      let customer = (
        await stripe.customers.list({
          email: customerEmail,
        })

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Compute cart.subtotal server-side as a positive integer (cents) before initiatePayment.
  2. For zero-amount carts (free items), short-circuit: skip Stripe and create the order directly.
  3. Ensure subtotal is a Number, not a string, before calling initiate.
  4. Validate amount >= 50 (Stripe's minimum in many currencies) to avoid Stripe-side rejections.

Example fix

// before: subtotal undefined or string
const cart = { items, subtotal: undefined }
// after: compute positive integer cents
const subtotal = items.reduce((s, i) => s + i.price * i.quantity, 0)
if (!(subtotal > 0)) throw new Error('Invalid subtotal')
const cart = { items, subtotal }
Defensive patterns

Strategy: validation

Validate before calling

function resolveAmount(subtotal: unknown): number {
  if (typeof subtotal !== 'number' || !Number.isFinite(subtotal) || subtotal <= 0) {
    throw new Error('A positive numeric subtotal (in smallest currency unit) is required')
  }
  return Math.round(subtotal)
}

// before initiatePayment — for zero-amount carts, skip Stripe and create the order directly
data.cart.subtotal = resolveAmount(data.cart.subtotal)

Type guard

export function isPositiveAmount(value: unknown): value is number {
  return typeof value === 'number' && Number.isFinite(value) && value > 0
}

Try / catch

try {
  await payments.initiatePayment({ data })
} catch (err) {
  if (err instanceof Error && /valid amount/.test(err.message)) {
    if (cart.subtotal === 0) {
      // free order — bypass Stripe
      return await createFreeOrder(cart)
    }
    return { ok: false, reason: 'invalid-amount' }
  }
  throw err
}

Prevention

When it happens

Trigger: cart.subtotal is undefined, null, a string, 0, or negative when initiatePayment runs. The check is `!amount || typeof amount !== 'number' || amount <= 0`.

Common situations: Cart subtotal not computed before checkout (client relies on server to total); free-cart edge case where subtotal legitimately is 0 (Stripe does not support zero-amount intents — use a different flow); subtotal stored as a string from a form; rounding producing 0 for tiny carts; currency-conversion bug yielding 0.

Related errors


AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12). Data as JSON: /api/errors/250ca595b487e8f9. Report an issue: GitHub.