n8n-io/n8n · error · NoNeedToReleaseEntityManagerError

Entity manager is not using single database connection and c

Error message

Entity manager is not using single database connection and cannot be released. Only entity managers created by connection#createEntityManagerWithSingleDatabaseConnection methods have a single database connection and they should be released.

What it means

EntityManager.release() is only meaningful for managers created via connection#createEntityManagerWithSingleDatabaseConnection (they own a single query runner). Calling release() on a default manager (which has no queryRunner) throws NoNeedToReleaseEntityManagerError. The guard prevents double-release and accidental release of pooled/shared managers.

Source

Thrown at packages/@n8n/typeorm/src/entity-manager/EntityManager.ts:1327

		if (entityRepositoryInstance instanceof AbstractRepository) {
			if (!(entityRepositoryInstance as any)['manager'])
				(entityRepositoryInstance as any)['manager'] = this;
		} else {
			if (!entityMetadata) throw new CustomRepositoryCannotInheritRepositoryError(customRepository);
			(entityRepositoryInstance as any)['manager'] = this;
			(entityRepositoryInstance as any)['metadata'] = entityMetadata;
		}

		return entityRepositoryInstance;
	}

	/**
	 * Releases all resources used by entity manager.
	 * This is used when entity manager is created with a single query runner,
	 * and this single query runner needs to be released after job with entity manager is done.
	 */
	async release(): Promise<void> {
		if (!this.queryRunner) throw new NoNeedToReleaseEntityManagerError();

		return this.queryRunner.release();
	}
}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Only call release() on managers you created explicitly via `connection.createQueryRunner().manager` (and pair with queryRunner.release()) or via `createEntityManagerWithSingleDatabaseConnection`.
  2. For the default manager (`connection.manager`), do not call release() — the DataSource owns it.
  3. Remove unconditional release() from finally blocks; gate it behind a flag indicating you created the manager.

Example fix

// before - releasing the shared default manager
const manager = dataSource.manager;
try { await manager.save(User, u); }
finally { await manager.release(); } // -> throws

// after - default manager is owned by the DataSource
const manager = dataSource.manager;
await manager.save(User, u);
// no release() — DataSource manages it
Defensive patterns

Strategy: validation

Validate before calling

function isOwnsQueryRunner(manager: EntityManager): boolean {
  return !!manager.queryRunner;
}
// only release managers you created explicitly
if (isOwnsQueryRunner(manager)) {
  await manager.release();
}

Prevention

When it happens

Trigger: Calling `manager.release()` on the default EntityManager obtained from `connection.manager` or `dataSource.manager`; calling release() twice; releasing a manager that was never tied to a single query runner.

Common situations: Generic cleanup code that always calls release() in finally; copy-paste from a single-connection example into multi-connection code; helper that wraps any manager and tries to release it.

Related errors


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