payloadcms/payload · error · Error

Currency must be provided for product validation.

Error message

Currency must be provided for product validation.

What it means

Thrown by defaultProductsValidation when the currency argument is falsy. The validator dynamically reads a per-currency price field (priceIn<CURRENCY>) on the product or variant, so without a currency it cannot decide which price to check. This guard runs before any price lookup and refuses to validate against an undefined currency.

Source

Thrown at packages/plugin-ecommerce/src/utilities/defaultProductsValidation.ts:13

import type { ProductsValidation } from '../types/index.js'

import { MissingPrice, OutOfStock } from './errorCodes.js'

export const defaultProductsValidation: ProductsValidation = ({
  currenciesConfig,
  currency,
  product,
  quantity = 1,
  variant,
}) => {
  if (!currency) {
    throw new Error('Currency must be provided for product validation.')
  }

  const priceField = `priceIn${currency.toUpperCase()}`

  if (variant) {
    if (!variant[priceField]) {
      throw new Error(`Variant with ID ${variant.id} does not have a price in ${currency}.`)
    }

    if (variant.inventory === 0 || (variant.inventory && variant.inventory < quantity)) {
      throw new Error(
        `Variant with ID ${variant.id} is out of stock or does not have enough inventory.`,
      )
    }
  } else if (product) {
    // Validate the product's details only if the variant is not provided as it can have its own inventory and price
    if (!product[priceField]) {
      throw new Error(`Product does not have a price in.`, {

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Pass the selected currency (e.g. 'usd') into every defaultProductsValidation call.
  2. Default currency from the plugin/store config if the caller omits it, then pass it through.
  3. Resolve currency once at the start of the checkout flow and thread it through every validation step.
  4. Add a runtime assertion on currency at the checkout entry point to fail fast with a clearer message.

Example fix

// before
defaultProductsValidation({ product, quantity })
// after
defaultProductsValidation({ currency: selectedCurrency, product, quantity })
Defensive patterns

Strategy: validation

Validate before calling

function resolveCurrencyForValidation(value: unknown, fallback?: string): string {
  if (typeof value === 'string' && value.length > 0) return value
  if (fallback) return fallback
  throw new Error('Currency must be provided for product validation')
}

// resolve once, thread through validation
const currency = resolveCurrencyForValidation(input.currency, storeDefaultCurrency)
defaultProductsValidation({ currency, product, quantity })

Type guard

export function isNonEmptyCurrency(value: unknown): value is string {
  return typeof value === 'string' && value.length > 0
}

Try / catch

try {
  defaultProductsValidation({ currency, product, quantity })
} catch (err) {
  if (err instanceof Error && /Currency must be provided/.test(err.message)) {
    // resolve currency from session/config and retry
    return defaultProductsValidation({ currency: storeDefaultCurrency, product, quantity })
  }
  throw err
}

Prevention

When it happens

Trigger: defaultProductsValidation is called (directly or via the cart/checkout pipeline) with currency undefined/null/empty. The function signature requires currency; omitting it triggers the guard.

Common situations: Cart pipeline invoked before currency selection; multi-currency store where the selected currency isn't passed into the validation step; a custom validation wrapper that drops currency; SSR with no currency in session; default currency not set on the plugin config.

Related errors


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