{"record":{"id":"4dcdbc964b59d3f7","repo":"payloadcms/payload","slug":"missingprice","errorCode":"MissingPrice","errorMessage":"Product does not have a price in.","messagePattern":"Product does not have a price in\\.","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/plugin-ecommerce/src/utilities/defaultProductsValidation.ts","lineNumber":31,"sourceCode":"    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.`, {\n        cause: { code: MissingPrice, codes: [product.id, currency] },\n      })\n    }\n\n    if (product.inventory === 0 || (product.inventory && product.inventory < quantity)) {\n      throw new Error(`Product is out of stock or does not have enough inventory.`, {\n        cause: { code: OutOfStock, codes: [product.id] },\n      })\n    }\n  }\n}\n","sourceCodeStart":13,"sourceCodeEnd":43,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/plugin-ecommerce/src/utilities/defaultProductsValidation.ts#L13-L43","documentation":"Thrown by defaultProductsValidation when no variant is supplied and the product itself has no value for the dynamic price field priceIn<CURRENCY>. The error carries an ErrorOptions cause with code 'MissingPrice' and codes [product.id, currency], so callers can inspect error.cause.code to distinguish it from a generic failure. Note the message text 'Product does not have a price in.' is truncated — the currency is not interpolated, but the cause.codes carries it.","triggerScenarios":"A cart item references a product (no variant) whose priceIn<CURRENCY> field is unset/falsy for the selected currency. Triggered during cart/checkout validation in the product branch.","commonSituations":"Multi-currency product with prices for some currencies but not the one selected; product created without all configured price fields; a currency added to currenciesConfig without backfilling existing products; data import that omitted price fields; frontend allowing checkout in an unsupported currency for that product.","solutions":["Backfill priceIn<CURRENCY> on the product for the requested currency.","Limit checkout currencies to those the product is priced in; hide the product otherwise.","Add an admin validation hook requiring all configured currency price fields on product create/update.","Inspect error.cause.code === 'MissingPrice' and error.cause.codes to surface a precise message to the customer."],"exampleFix":"// before: product missing priceInEUR\nconst product = { id: 1, priceInUSD: 2000 } // EUR checkout fails with MissingPrice\n// after: backfill the price\nconst product = { id: 1, priceInUSD: 2000, priceInEUR: 1850 }","handlingStrategy":"try-catch","validationCode":"function productHasPriceInCurrency(product: Record<string, unknown>, currency: string): boolean {\n  const field = `priceIn${currency.toUpperCase()}`\n  const v = product[field]\n  return typeof v === 'number' ? v > 0 : Boolean(v)\n}\n\nif (!productHasPriceInCurrency(product, currency)) {\n  const e = new Error(`Product ${product.id} has no price in ${currency}`)\n  ;(e as any).cause = { code: 'MissingPrice', codes: [product.id, currency] }\n  throw e\n}","typeGuard":"export function productHasPrice(product: Record<string, unknown>, currency: string): boolean {\n  const v = product[`priceIn${currency.toUpperCase()}`]\n  return typeof v === 'number' ? v > 0 : Boolean(v)\n}","tryCatchPattern":"try {\n  defaultProductsValidation({ currency, product, quantity })\n} catch (err) {\n  const cause = (err as Error & { cause?: { code?: string } }).cause\n  if (cause?.code === 'MissingPrice') {\n    // data gap — backfill or hide the product for this currency\n    return { ok: false, reason: 'product-missing-price', productId: product.id, currency }\n  }\n  throw err\n}","preventionTips":["Backfill priceIn<CURRENCY> on products whenever a new currency is added to currenciesConfig.","Add an admin hook requiring all configured currency price fields on product create/update.","Restrict checkout currencies to those the product is priced in; hide unsupported combinations.","Inspect error.cause.code === 'MissingPrice' to distinguish this from generic validation failures."],"tags":["validation","product","price","currency","ecommerce","data-integrity","error-code"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}