{"record":{"id":"e762417ab2469091","repo":"payloadcms/payload","slug":"currency-must-be-provided-for-product-validation","errorCode":null,"errorMessage":"Currency must be provided for product validation.","messagePattern":"Currency must be provided for product validation\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/plugin-ecommerce/src/utilities/defaultProductsValidation.ts","lineNumber":13,"sourceCode":"import type { ProductsValidation } from '../types/index.js'\n\nimport { MissingPrice, OutOfStock } from './errorCodes.js'\n\nexport const defaultProductsValidation: ProductsValidation = ({\n  currenciesConfig,\n  currency,\n  product,\n  quantity = 1,\n  variant,\n}) => {\n  if (!currency) {\n    throw new Error('Currency must be provided for product validation.')\n  }\n\n  const priceField = `priceIn${currency.toUpperCase()}`\n\n  if (variant) {\n    if (!variant[priceField]) {\n      throw new Error(`Variant with ID ${variant.id} does not have a price in ${currency}.`)\n    }\n\n    if (variant.inventory === 0 || (variant.inventory && variant.inventory < quantity)) {\n      throw new Error(\n        `Variant with ID ${variant.id} is out of stock or does not have enough inventory.`,\n      )\n    }\n  } else if (product) {\n    // Validate the product's details only if the variant is not provided as it can have its own inventory and price\n    if (!product[priceField]) {\n      throw new Error(`Product does not have a price in.`, {","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/plugin-ecommerce/src/utilities/defaultProductsValidation.ts#L1-L31","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass the selected currency (e.g. 'usd') into every defaultProductsValidation call.","Default currency from the plugin/store config if the caller omits it, then pass it through.","Resolve currency once at the start of the checkout flow and thread it through every validation step.","Add a runtime assertion on currency at the checkout entry point to fail fast with a clearer message."],"exampleFix":"// before\ndefaultProductsValidation({ product, quantity })\n// after\ndefaultProductsValidation({ currency: selectedCurrency, product, quantity })","handlingStrategy":"validation","validationCode":"function resolveCurrencyForValidation(value: unknown, fallback?: string): string {\n  if (typeof value === 'string' && value.length > 0) return value\n  if (fallback) return fallback\n  throw new Error('Currency must be provided for product validation')\n}\n\n// resolve once, thread through validation\nconst currency = resolveCurrencyForValidation(input.currency, storeDefaultCurrency)\ndefaultProductsValidation({ currency, product, quantity })","typeGuard":"export function isNonEmptyCurrency(value: unknown): value is string {\n  return typeof value === 'string' && value.length > 0\n}","tryCatchPattern":"try {\n  defaultProductsValidation({ currency, product, quantity })\n} catch (err) {\n  if (err instanceof Error && /Currency must be provided/.test(err.message)) {\n    // resolve currency from session/config and retry\n    return defaultProductsValidation({ currency: storeDefaultCurrency, product, quantity })\n  }\n  throw err\n}","preventionTips":["Resolve currency once at checkout entry and pass it to every validation call.","Default to the store's base currency when the customer hasn't selected one.","Add a runtime assertion on currency at the checkout boundary to fail fast.","Type the validation function so currency is required, preventing accidental omission."],"tags":["validation","currency","ecommerce","product","input-contract"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}