{"record":{"id":"70750551d858cbc5","repo":"medusajs/medusa","slug":"could-not-find-all-existing-links-from-data","errorCode":null,"errorMessage":"Could not find all existing links from data","messagePattern":"Could not find all existing links from data","errorType":"exception","errorClass":"MedusaError","httpStatus":404,"severity":"error","filePath":"packages/core/core-flows/src/common/steps/update-remote-links.ts","lineNumber":50,"sourceCode":" */\nexport const updateRemoteLinksStep = createStep(\n  updateRemoteLinksStepId,\n  async (data: LinkDefinition[], { container }) => {\n    if (!data?.length) {\n      return new StepResponse([], [])\n    }\n\n    const link = container.resolve<Link>(ContainerRegistrationKeys.LINK)\n\n    // Fetch all existing links and throw an error if any weren't found\n    const dataBeforeUpdate = (await link.list(data, {\n      asLinkDefinition: true,\n    })) as LinkDefinition[]\n\n    const unequal = dataBeforeUpdate.length !== data.length\n\n    if (unequal) {\n      throw new MedusaError(\n        MedusaError.Types.NOT_FOUND,\n        `Could not find all existing links from data`\n      )\n    }\n\n    // link.create here performs an upsert. By performing validation above, we can ensure\n    // that this method will always perform an update in these cases\n    await link.create(data)\n\n    return new StepResponse(data, dataBeforeUpdate)\n  },\n  async (dataBeforeUpdate, { container }) => {\n    if (!dataBeforeUpdate?.length) {\n      return\n    }\n\n    const link = container.resolve<Link>(ContainerRegistrationKeys.LINK)\n","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/core/core-flows/src/common/steps/update-remote-links.ts#L32-L68","documentation":"Thrown by updateRemoteLinksStep when the number of existing link rows fetched before update does not match the number of entries in the input data. The step validates that every link passed in already exists before upserting; a mismatch means at least one link could not be found.","triggerScenarios":"Calling updateRemoteLinksStep (directly or via a workflow that refreshes links, e.g. cart/payment/order promotion links) where one of the link definitions references a nonexistent or already-deleted counterpart, so the pre-update query returns fewer rows than data.length.","commonSituations":"Passing stale link data referencing deleted records; partial deletion of one side of a link (manual DB cleanup); race where a link was removed concurrently; wrong field names in the LinkDefinition so the lookup misses.","solutions":["Inspect each entry in data and verify both sides (e.g. cart_id and promotion_id) still exist before calling the step","Re-query the links via link.list() and pass the fresh link records instead of hand-built definitions","Ensure you are creating links (createRemoteLinkStep) first if they may not exist yet"],"exampleFix":"// before\nawait updateRemoteLinksStep(container).run({\n  input: [ { [Modules.CART]: { cart_id }, [Modules.PROMOTION]: { promotion_id } , data: {...} } ],\n})\n\n// after: only update links that actually exist\nconst existing = await link.list(MODULES_LINK, { cart_id })\nconst toUpdate = existing.filter((l) => promoIds.includes(l.promotion_id))\nawait updateRemoteLinksStep(container).run({ input: toUpdate })","handlingStrategy":"validation","validationCode":"const existing = await link.list(cartPromotionLink, { cart_id })\nconst valid = input.filter((d) => existing.some((l) => l.promotion_id === d[Modules.PROMOTION].promotion_id))\nif (valid.length !== input.length) throw new Error(\"Some links no longer exist\")","typeGuard":"const isLinkDefinition = (d: unknown): d is LinkDefinition => !!d && typeof d === \"object\"","tryCatchPattern":"try { await updateRemoteLinksStep(scope).run({ input }) } catch (e) { if (e.type === MedusaError.Types.NOT_FOUND) { /* refetch links and retry with fresh data */ } throw e }","preventionTips":["Never hand-build link definitions from stale ids; re-query first","Avoid partial manual deletes of one side of a link","Log both sides of failed link lookups"],"tags":["links","remote-links","data-integrity","core-flows"],"backgroundTag":"link-not-found","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}