n8n-io/n8n · error · CircularRelationsError

Circular relations detected: ${path}. To resolve this issue

Error message

Circular relations detected: ${path}. To resolve this issue you need to set nullable: true somewhere in this dependency structure.

What it means

TypeORM builds a dependency graph where each non-nullable join-column relation adds an edge from the entity to its inverse, then calls `graph.overallOrder()` to topologically sort entities for INSERT ordering. If the sort reports a dependency cycle, `CircularRelationsError` is thrown: two or more entities mutually require each other through NOT NULL foreign keys, so none can be inserted first.

Source

Thrown at packages/@n8n/typeorm/src/metadata-builder/EntityMetadataValidator.ts:266

	/**
	 * Validates dependencies of the entity metadatas.
	 */
	protected validateDependencies(entityMetadatas: EntityMetadata[]) {
		const graph = new DepGraph();
		entityMetadatas.forEach((entityMetadata) => {
			graph.addNode(entityMetadata.name);
		});
		entityMetadatas.forEach((entityMetadata) => {
			entityMetadata.relationsWithJoinColumns
				.filter((relation) => !relation.isNullable)
				.forEach((relation) => {
					graph.addDependency(entityMetadata.name, relation.inverseEntityMetadata.name);
				});
		});
		try {
			graph.overallOrder();
		} catch (err) {
			throw new CircularRelationsError(
				err.toString().replace('Error: Dependency Cycle Found: ', ''),
			);
		}
	}

	/**
	 * Validates eager relations to prevent circular dependency in them.
	 */
	protected validateEagerRelations(entityMetadatas: EntityMetadata[]) {
		entityMetadatas.forEach((entityMetadata) => {
			entityMetadata.eagerRelations.forEach((relation) => {
				if (relation.inverseRelation && relation.inverseRelation.isEager)
					throw new TypeORMError(
						`Circular eager relations are disallowed. ` +
							`${entityMetadata.targetName}#${relation.propertyPath} contains "eager: true", and its inverse side ` +
							`${relation.inverseEntityMetadata.targetName}#${relation.inverseRelation.propertyPath} contains "eager: true" as well.` +
							` Remove "eager: true" from one side of the relation.`,
					);

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Set `nullable: true` on at least one join column in the cycle (the error message's own guidance) so TypeORM can insert, then update the FK in a second step.
  2. Break the cycle in application code: insert parent without FK, then UPDATE the FK once the child exists.
  3. Use a junction table (@ManyToMany) for the mutual dependency so neither side carries a mandatory FK.

Example fix

// before — both sides NOT NULL → cycle
@ManyToOne(() => B, { nullable: false }) b: B;
@ManyToOne(() => A, { nullable: false }) a: A;

// after — break the cycle
@ManyToOne(() => B, { nullable: true }) b: B | null;
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: detect cycles among non-nullable join-column relations
const deps = new Map<string, string[]>();
for (const m of dataSource.entityMetadatas) deps.set(m.name, []);
for (const m of dataSource.entityMetadatas) {
  for (const r of m.relationsWithJoinColumns) {
    if (!r.isNullable) deps.get(m.name)!.push(r.inverseEntityMetadata.name);
  }
}
// run a DFS cycle check on `deps` before calling initialize's schema build

Try / catch

try { await dataSource.initialize(); } catch (e) { if (e instanceof CircularRelationsError) { console.error('Cycle path:', e.message); } throw e; }

Prevention

When it happens

Trigger: Entities A and B each carry a `@ManyToOne(() => Other, { nullable: false })` pointing at the other (or a longer cycle A->B->C->A) with all join columns non-nullable. Defining `@JoinColumn({ nullable: false })` on both sides of a mutual relation.

Common situations: Modeling a two-way mandatory ownership (user must have a profile, profile must have a user) where neither side is allowed null. Forgetting `nullable: true` on at least one side of a co-dependent pair.

Related errors


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