{"record":{"id":"69268d4107deaa28","repo":"medusajs/medusa","slug":"many-to-one-relation-relation-name-must-be-set","errorCode":null,"errorMessage":"Many-to-one relation ${relation.name} must be set with an ID","messagePattern":"Many-to-one relation (.+?) must be set with an ID","errorType":"validation","errorClass":"MedusaError","httpStatus":400,"severity":"error","filePath":"packages/core/utils/src/dal/mikro-orm/mikro-orm-repository.ts","lineNumber":1243,"sourceCode":"\n      // If it is a many-to-one we ensure the ID is set for when we want to set/unset an association\n      if (relation.kind === ReferenceKind.MANY_TO_ONE) {\n        if (originalData === null) {\n          entryCopy[relation.joinColumns[0]] = null\n          return null\n        }\n\n        // The relation can either be a primitive or the entity object, depending on how it's defined on the model\n        let relationId\n        if (isString(originalData)) {\n          relationId = originalData\n        } else if (\"id\" in originalData) {\n          relationId = originalData.id\n        }\n\n        // We don't support creating many-to-one relations, so we want to throw if someone doesn't pass the ID\n        if (!relationId) {\n          throw new MedusaError(\n            MedusaError.Types.INVALID_DATA,\n            `Many-to-one relation ${relation.name} must be set with an ID`\n          )\n        }\n\n        entryCopy[relation.joinColumns[0]] = relationId\n        return originalData\n      }\n\n      return undefined\n    }\n\n    // Returns a POJO object with the ID populated from the entity model hooks\n    protected getEntityWithId(\n      manager: SqlEntityManager,\n      entityName: string,\n      data: any\n    ): Record<string, any> & { id: string } {","sourceCodeStart":1225,"sourceCodeEnd":1261,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/core/utils/src/dal/mikro-orm/mikro-orm-repository.ts#L1225-L1261","documentation":"Thrown while building the write payload in mikro-orm-repository.ts: a many-to-one relation was supplied as a nested object without an `id` property (and no other ID source), and Medusa does not support creating the related entity inline during this upsert. Many-to-one relations must be set by referencing an existing ID.","triggerScenarios":"Upserting with payload { variant: { title: 'x', options: {...} } } where `variant` is many-to-one and the object carries no id; passing a partially-built object (e.g. from a form) instead of { id: 'variant_123' }; passing an object whose id field is undefined after destructuring.","commonSituations":"Admin/API payloads that embed full nested objects instead of IDs; assuming create-or-connect semantics (upsertWithReplace does not create many-to-one targets); data transformations that strip or rename the id key; migrating from a flow that previously created the child entity separately.","solutions":["Change the nested object to reference an existing entity: { relation: { id: 'existing_id' } } or set the FK field directly (relation_id).","If the related entity does not exist yet, create it first with its own service call, then pass its returned ID in the upsert.","If the field is actually a one-to-many/many-to-many managed relation, restructure the payload so the parent owns the array of children rather than the reverse."],"exampleFix":"// before\nawait pricingService.upsert([\n  { price_set: { name: 'default' } }, // many-to-one without id\n])\n\n// after\nconst set = await pricingService.createPriceSets([{ name: 'default' }])\nawait pricingService.upsert([\n  { price_set: { id: set[0].id } }, // set with an ID\n])","handlingStrategy":"validation","validationCode":"for (const item of payload) {\n  for (const [key, value] of Object.entries(item)) {\n    if (value && typeof value === 'object' && !('id' in value) && isManyToOne(key)) {\n      throw new Error(`Relation ${key} must reference an existing id`)\n    }\n  }\n}","typeGuard":"function hasId(v: unknown): v is { id: string } {\n  return typeof v === 'object' && v !== null && typeof (v as any).id === 'string' && (v as any).id.length > 0\n}","tryCatchPattern":null,"preventionTips":["Create related entities first, then reference them by id in upsert payloads.","Sanitize API input so nested objects without ids are rejected with a clear 400.","Keep FK helper fields (e.g. customer_id) as the canonical way to set many-to-one links."],"tags":["mikro-orm","upsert","many-to-one","relation","invalid-data"],"backgroundTag":"missing-relation-id-on-upsert","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}