{"record":{"id":"0254a05b5302e78b","repo":"n8n-io/n8n","slug":"add-operation-is-only-supported-for-many-to-many-a","errorCode":null,"errorMessage":"Add operation is only supported for many-to-many and one-to-many relations. However given \"${relation.propertyPath}\" has ${relation.relationType} relation. Use .set() method instead.","messagePattern":"Add operation is only supported for many-to-many and one-to-many relations\\. However given \"(.+?)\" has (.+?) relation\\. Use \\.set\\(\\) method instead\\.","errorType":"exception","errorClass":"TypeORMError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/typeorm/src/query-builder/RelationQueryBuilder.ts","lineNumber":94,"sourceCode":"\t * Adds (binds) given value to entity relation.\n\t * Value can be entity, entity id or entity id map (if entity has composite ids).\n\t * Value also can be array of entities, array of entity ids or array of entity id maps (if entity has composite ids).\n\t * Works only for many-to-many and one-to-many relations.\n\t * For many-to-one and one-to-one use #set method instead.\n\t */\n\tasync add(value: any | any[]): Promise<void> {\n\t\tif (Array.isArray(value) && value.length === 0) return;\n\n\t\tconst relation = this.expressionMap.relationMetadata;\n\n\t\tif (!this.expressionMap.of)\n\t\t\t// todo: move this check before relation query builder creation?\n\t\t\tthrow new TypeORMError(\n\t\t\t\t`Entity whose relation needs to be set is not set. Use .of method to define whose relation you want to set.`,\n\t\t\t);\n\n\t\tif (relation.isManyToOne || relation.isOneToOne)\n\t\t\tthrow new TypeORMError(\n\t\t\t\t`Add operation is only supported for many-to-many and one-to-many relations. ` +\n\t\t\t\t\t`However given \"${relation.propertyPath}\" has ${relation.relationType} relation. ` +\n\t\t\t\t\t`Use .set() method instead.`,\n\t\t\t);\n\n\t\t// if there are multiple join columns then user must send id map as \"value\" argument. check if he really did it\n\t\tif (\n\t\t\trelation.joinColumns &&\n\t\t\trelation.joinColumns.length > 1 &&\n\t\t\t(!ObjectUtils.isObject(value) || Object.keys(value).length < relation.joinColumns.length)\n\t\t)\n\t\t\tthrow new TypeORMError(\n\t\t\t\t`Value to be set into the relation must be a map of relation ids, for example: .set({ firstName: \"...\", lastName: \"...\" })`,\n\t\t\t);\n\n\t\tconst updater = new RelationUpdater(this, this.expressionMap);\n\t\treturn updater.update(value);\n\t}","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/typeorm/src/query-builder/RelationQueryBuilder.ts#L76-L112","documentation":"RelationQueryBuilder.add is the inverse of .set: it only operates on collection relations (many-to-many, one-to-many). If the resolved relation is many-to-one or one-to-one it throws TypeORMError directing the developer to .set() instead, because adding to a single-valued FK is not a collection mutation.","triggerScenarios":"qb.relation(User,'profile').of(u).add(profile) where profile is @OneToOne; .add() on a @ManyToOne like User.organization.","commonSituations":"Developer assumes all relations support .add(); decorator confusion; copy-paste from a tags relation onto a profile relation.","solutions":["Use .set() for single-valued relations: qb.relation(User,'profile').of(u).set(profile).","Confirm the decorator on relation.propertyPath; if it really is a collection, the relation metadata may be on the wrong side.","For replacing a single-valued FK to null, use .set(null)."],"exampleFix":"// before\nawait qb.relation(User,'profile').of(u).add(profile); // profile is one-to-one\n// after\nawait qb.relation(User,'profile').of(u).set(profile);","handlingStrategy":"type-guard","validationCode":"function supportsAdd(ds: DataSource, target: Function, path: string): boolean {\n  const r = ds.getMetadata(target).findRelationWithPropertyPath(path);\n  return !!r && (r.isManyToMany || r.isOneToMany);\n}","typeGuard":"function isCollectionRelation(ds: DataSource, target: Function, path: string): boolean {\n  const r = ds.getMetadata(target).findRelationWithPropertyPath(path);\n  return !!r && (r.relationType === 'many-to-many' || r.relationType === 'one-to-many');\n}","tryCatchPattern":null,"preventionTips":["Document the decorator->API matrix in the data-access layer README.","Centralize relation mutation behind a service that picks add vs set from metadata."],"tags":["typeorm","relation-query-builder","add","relation-type"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}