{"record":{"id":"81327e5c362446a3","repo":"medusajs/medusa","slug":"product-with-id-req-params-id-not-found","errorCode":null,"errorMessage":"Product with id \"${req.params.id}\" not found","messagePattern":"Product with id \"(.+?)\" not found","errorType":"exception","errorClass":"MedusaError","httpStatus":404,"severity":"error","filePath":"packages/medusa/src/api/admin/products/[id]/route.ts","lineNumber":52,"sourceCode":"  req: AuthenticatedMedusaRequest<\n    HttpTypes.AdminUpdateProduct & AdditionalData,\n    HttpTypes.SelectParams\n  >,\n  res: MedusaResponse<HttpTypes.AdminProductResponse>\n) => {\n  const { additional_data, ...update } = req.validatedBody\n\n  const existingProduct = await refetchEntity({\n    entity: \"product\",\n    idOrFilter: req.params.id,\n    scope: req.scope,\n    fields: [\"id\"],\n  })\n  /**\n   * Check if the product exists with the id or not before calling the workflow.\n   */\n  if (!existingProduct) {\n    throw new MedusaError(\n      MedusaError.Types.NOT_FOUND,\n      `Product with id \"${req.params.id}\" not found`\n    )\n  }\n\n  const { result } = await updateProductsWorkflow(req.scope).run({\n    input: {\n      selector: { id: req.params.id },\n      update,\n      additional_data,\n    },\n  })\n\n  const product = await refetchEntity({\n    entity: \"product\",\n    idOrFilter: result[0].id,\n    scope: req.scope,\n    fields: remapKeysForProduct(req.queryConfig.fields ?? []),","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/medusa/src/api/admin/products/[id]/route.ts#L34-L70","documentation":"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.","triggerScenarios":"Calling POST /admin/products/prod_123 with an update body for a product that does not exist or was deleted.","commonSituations":"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.","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"],"exampleFix":"// before\nawait sdk.admin.product.update(prodId, { title: \"New\" })\n\n// after\ntry {\n  await sdk.admin.product.update(prodId, { title: \"New\" })\n} catch (e) {\n  if (e.statusCode === 404) { console.warn(`product ${prodId} deleted; skipped`); return }\n  throw e\n}","handlingStrategy":"try-catch","validationCode":"const { products } = await sdk.admin.product.list({ id: [prodId], fields: \"id\" })\nif (products.length === 0) throw new Error(`Product ${prodId} gone; recreate or skip`)","typeGuard":null,"tryCatchPattern":"try {\n  await sdk.admin.product.update(prodId, patch)\n} catch (e: any) {\n  if (e.statusCode === 404) { skipped.push(prodId); return }\n  throw e\n}","preventionTips":["Batch editors: refresh ids before applying changes","Sync jobs: reconcile with list endpoint first","Log skipped-on-404 records for review"],"tags":["admin","products","not-found","rest-api"],"backgroundTag":"resource-not-found","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}