medusajs/medusa · error · MedusaError

Product with id "${req.params.id}" not found

Error message

Product with id "${req.params.id}" not found

What it means

Thrown by POST /admin/products/:id when the pre-update existence check (fields: ["id"]) finds no product. The route deliberately checks existence before dispatching updateProductsWorkflow so the workflow fails fast with a clear message.

Source

Thrown at packages/medusa/src/api/admin/products/[id]/route.ts:52

  req: AuthenticatedMedusaRequest<
    HttpTypes.AdminUpdateProduct & AdditionalData,
    HttpTypes.SelectParams
  >,
  res: MedusaResponse<HttpTypes.AdminProductResponse>
) => {
  const { additional_data, ...update } = req.validatedBody

  const existingProduct = await refetchEntity({
    entity: "product",
    idOrFilter: req.params.id,
    scope: req.scope,
    fields: ["id"],
  })
  /**
   * Check if the product exists with the id or not before calling the workflow.
   */
  if (!existingProduct) {
    throw new MedusaError(
      MedusaError.Types.NOT_FOUND,
      `Product with id "${req.params.id}" not found`
    )
  }

  const { result } = await updateProductsWorkflow(req.scope).run({
    input: {
      selector: { id: req.params.id },
      update,
      additional_data,
    },
  })

  const product = await refetchEntity({
    entity: "product",
    idOrFilter: result[0].id,
    scope: req.scope,
    fields: remapKeysForProduct(req.queryConfig.fields ?? []),

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Re-fetch the product before updating; treat 404 as 'skip or recreate' in sync logic
  2. Refresh product lists in batch editors after deletions
  3. For sync jobs, reconcile against GET /admin/products before pushing updates

Example fix

// before
await sdk.admin.product.update(prodId, { title: "New" })

// after
try {
  await sdk.admin.product.update(prodId, { title: "New" })
} catch (e) {
  if (e.statusCode === 404) { console.warn(`product ${prodId} deleted; skipped`); return }
  throw e
}
Defensive patterns

Strategy: try-catch

Validate before calling

const { products } = await sdk.admin.product.list({ id: [prodId], fields: "id" })
if (products.length === 0) throw new Error(`Product ${prodId} gone; recreate or skip`)

Try / catch

try {
  await sdk.admin.product.update(prodId, patch)
} catch (e: any) {
  if (e.statusCode === 404) { skipped.push(prodId); return }
  throw e
}

Prevention

When it happens

Trigger: Calling POST /admin/products/prod_123 with an update body for a product that does not exist or was deleted.

Common situations: Two admins editing the same product with one deleting it, batch editors holding stale ids, or automated sync jobs pushing updates for products removed from the store.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27). Data as JSON: /api/errors/81327e5c362446a3. Report an issue: GitHub.