n8n-io/n8n · error · FindRelationsNotFoundError

Relation "${notFoundRelations[0]}" was not found; please che

Error message

Relation "${notFoundRelations[0]}" was not found; please check if it is correct and really exists in your entity.

What it means

FindOptionsUtils applies options.relations recursively, removing matched relations from a working array. Anything left unmatched means the caller asked for a relation that doesn't exist on the entity graph; FindRelationsNotFoundError is thrown with the leftover names (singular form shown when one remains).

Source

Thrown at packages/@n8n/typeorm/src/find-options/FindOptionsUtils.ts:135

                    throw new TypeORMError(`${select} column was not found in the ${metadata.name} entity.`);

                const columns = metadata.findColumnsWithPropertyPath(`${select}`);

                for (const column of columns) {
                    qb.addSelect(qb.alias + "." + column.propertyPath);
                }
            });
        }

        if (options.relations) {
            // Copy because `applyRelationsRecursively` modifies it
            const allRelations = [...options.relations];
            this.applyRelationsRecursively(qb, allRelations, qb.expressionMap.mainAlias!.name, qb.expressionMap.mainAlias!.metadata, "");
            // recursive removes found relations from allRelations array
            // if there are relations left in this array it means those relations were not found in the entity structure
            // so, we give an exception about not found relations
            if (allRelations.length > 0)
                throw new FindRelationsNotFoundError(allRelations);
        }

        if (options.join) {
            if (options.join.leftJoin)
                Object.keys(options.join.leftJoin).forEach(key => {
                    qb.leftJoin(options.join!.leftJoin![key], key);
                });

            if (options.join.innerJoin)
                Object.keys(options.join.innerJoin).forEach(key => {
                    qb.innerJoin(options.join!.innerJoin![key], key);
                });

            if (options.join.leftJoinAndSelect)
                Object.keys(options.join.leftJoinAndSelect).forEach(key => {
                    qb.leftJoinAndSelect(options.join!.leftJoinAndSelect![key], key);
                });

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Check the @OneToMany/@ManyToOne/@ManyToMany decorators on the entity and use the exact relation property name.
  2. For nested relations, confirm each segment of the dotted path is a relation on the corresponding entity.
  3. Update call sites after renaming any relation property.
  4. If you only want the FK column, use `select` not `relations`.

Example fix

// before
await repo.find({ relations: ['tag'] }); // entity has `tags`

// after
@Entity()
class Post { @ManyToMany(() => Tag) tags!: Tag[]; }
await repo.find({ relations: ['tags'] });
Defensive patterns

Strategy: validation

Validate before calling

function validateRelations<Entity>(meta: import('@n8n/typeorm').EntityMetadata<Entity>, relations: readonly string[]): void {
  for (const r of relations) {
    const segs = r.split('.');
    let m = meta;
    for (const seg of segs) {
      const rel = m.relations.find(x => x.propertyPath === seg);
      if (!rel) throw new Error(`relation ${r} not found on ${m.name}`);
      m = rel.inverseEntityMetadata;
    }
  }
}
validateRelations(connection.getMetadata(Entity), options.relations ?? []);
await repo.findOne(options);

Type guard

function isRelationPath<Entity>(meta: import('@n8n/typeorm').EntityMetadata<Entity>, path: string): boolean {
  let m = meta; const segs = path.split('.');
  for (const seg of segs) {
    const rel = m.relations.find(x => x.propertyPath === seg);
    if (!rel) return false;
    m = rel.inverseEntityMetadata;
  }
  return true;
}

Prevention

When it happens

Trigger: Passing `relations: ['tags']` when the entity has no `tags` relation; typos in the relation path; requesting nested relations like `'profile.avatar'` where `profile` exists but `avatar` isn't a relation of Profile; mixing relation names with column names; relation was renamed in code but call sites weren't updated.

Common situations: Rename of a relation missing some call sites; copy-paste between entities; switch from eager loading to explicit relations where the field is a @Column not a @ManyToOne; nested paths where a segment isn't itself a relation.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/93282be09f140e29. Report an issue: GitHub.