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
- Re-fetch the product before updating; treat 404 as 'skip or recreate' in sync logic
- Refresh product lists in batch editors after deletions
- 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
- Batch editors: refresh ids before applying changes
- Sync jobs: reconcile with list endpoint first
- Log skipped-on-404 records for review
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
- Product not found
- Invite with id: ${id} was not found
- Price list with id: ${id} was not found
- Product category with id: ${req.params.id} was not found
- Product option value with id "${valueId}" was not found for
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/81327e5c362446a3.
Report an issue: GitHub.