{"record":{"id":"1af45a6c8e038aaf","repo":"medusajs/medusa","slug":"inventory-availability-cannot-be-calculated-in-the","errorCode":null,"errorMessage":"Inventory availability cannot be calculated in the given context. Either provide a single sales channel id or configure a single sales channel in the publishable key","messagePattern":"Inventory availability cannot be calculated in the given context\\. Either provide a single sales channel id or configure a single sales channel in the publishable key","errorType":"validation","errorClass":"MedusaError","httpStatus":400,"severity":"error","filePath":"packages/medusa/src/api/utils/middlewares/products/variant-inventory-quantity.ts","lineNumber":75,"sourceCode":"}\n\nexport const wrapVariantsWithInventoryQuantityForSalesChannel = async (\n  req: MedusaStoreRequest<unknown>,\n  variants: VariantInput[]\n) => {\n  const salesChannelIds = transformAndValidateSalesChannelIds(req)\n\n  const publishableApiKeySalesChannelIds =\n    req.publishable_key_context.sales_channel_ids ?? []\n\n  let channelsToUse: string\n\n  if (publishableApiKeySalesChannelIds.length === 1) {\n    channelsToUse = publishableApiKeySalesChannelIds[0]\n  } else if (salesChannelIds.length === 1) {\n    channelsToUse = salesChannelIds[0]\n  } else {\n    throw new MedusaError(\n      MedusaError.Types.INVALID_DATA,\n      `Inventory availability cannot be calculated in the given context. Either provide a single sales channel id or configure a single sales channel in the publishable key`\n    )\n  }\n\n  const variantsToWrap = (variants ?? []).filter(\n    (variant): variant is VariantInput => !!variant?.id\n  )\n  const variantIds = variantsToWrap.map((variant) => variant.id)\n\n  if (!variantIds.length) {\n    return\n  }\n\n  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)\n  const availability = await getVariantAvailability(query, {\n    variant_ids: variantIds,\n    sales_channel_id: channelsToUse,","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/medusa/src/api/utils/middlewares/products/variant-inventory-quantity.ts#L57-L93","documentation":"Thrown by wrapVariantsWithInventoryQuantityForSalesChannel when calculating variant inventory availability requires exactly one sales channel but the context yields zero or several: neither the publishable key nor the request narrows it to a single channel. Inventory quantities are per-location/stock-location tied to sales channels, so 'in stock' is undefined across multiple channels at once.","triggerScenarios":"Requesting variants with inventory (e.g. listing product variants through this middleware) when the publishable key has 2+ sales channels AND the request's sales_channel_id filter is absent or contains 2+ ids (or both resolve to none).","commonSituations":"Publishable key linked to multiple sales channels (e.g. web + app) and the storefront doesn't pin a channel; passing an array of sales_channel_id values expecting aggregated availability.","solutions":["Add a single sales_channel_id query param to the request","Restrict the publishable key to exactly one sales channel if the storefront only serves one","If multiple channels are intentional, fetch inventory per channel with separate requests"],"exampleFix":"// before\nGET /store/products/variants (key has sc_web + sc_app, no filter)\n\n// after\nGET /store/products/variants?sales_channel_id=sc_web","handlingStrategy":"validation","validationCode":"// resolve exactly one channel before requesting inventory availability\nconst { sales_channels } = await fetch('/store/sales-channels', {\n  headers: { 'x-publishable-api-key': PK },\n}).then(r => r.json())\nconst channelId = requestedScId ?? (sales_channels.length === 1 ? sales_channels[0].id : null)\nif (!channelId) throw new Error('pin a single sales channel')\n// then pass sales_channel_id: channelId on the request","typeGuard":"const hasSingleChannel = (\n  filterIds: string[] | undefined,\n  keyChannelIds: string[]\n): boolean => keyChannelIds.length === 1 || (filterIds?.length ?? 0) === 1","tryCatchPattern":"try {\n  await listVariantsWithInventory()\n} catch (e) {\n  if (e.type === 'invalid_data' && /Inventory availability/.test(e.message)) {\n    // retry with an explicit single sales_channel_id\n  }\n  throw e\n}","preventionTips":["Pin a single sales_channel_id in storefront requests whenever inventory is displayed","Link one publishable key per storefront/channel rather than sharing multi-channel keys"],"tags":["inventory","sales-channel","publishable-key","store-api"],"backgroundTag":"ambiguous-sales-channel-context","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}