n8n-io/n8n · error · CustomRepositoryCannotInheritRepositoryError

Custom entity repository ${repository.name} cannot inherit R

Error message

Custom entity repository ${repository.name} cannot inherit Repository class without entity being set in the @EntityRepository decorator.

What it means

In getCustomRepository, when the registered custom repository extends the plain Repository class (not AbstractRepository), TypeORM needs entity metadata to bind it. If the @EntityRepository decorator was applied without an entity argument (so entityRepositoryMetadataArgs.entity is undefined), and the class extends Repository, CustomRepositoryCannotInheritRepositoryError is thrown. AbstractRepository-based repos don't need an entity; Repository-based ones do.

Source

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

			},
		);
		if (!entityRepositoryMetadataArgs) throw new CustomRepositoryNotFoundError(customRepository);

		const entityMetadata = entityRepositoryMetadataArgs.entity
			? this.connection.getMetadata(entityRepositoryMetadataArgs.entity)
			: undefined;
		const entityRepositoryInstance = new (entityRepositoryMetadataArgs.target as any)(
			this,
			entityMetadata,
		);

		// NOTE: dynamic access to protected properties. We need this to prevent unwanted properties in those classes to be exposed,
		// however we need these properties for internal work of the class
		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. Pass the entity to the decorator: `@EntityRepository(User)` on Repository-extending classes.
  2. If the repo intentionally serves multiple entities, extend `AbstractRepository` instead and use the injected `this.manager`.
  3. Keep the rule of thumb: extends Repository<Entity> ⇒ @EntityRepository(Entity); extends AbstractRepository ⇒ @EntityRepository() is fine.

Example fix

// before
@EntityRepository()
class UserRepo extends Repository<User> { /* ... */ }

// after - supply the entity
@EntityRepository(User)
class UserRepo extends Repository<User> { /* ... */ }
Defensive patterns

Strategy: validation

Validate before calling

import { getMetadataArgsStorage } from '@n8n/typeorm';
import { Repository, AbstractRepository } from '@n8n/typeorm';
function assertRepoDecorationConsistent(repo: Function): void {
  const meta = getMetadataArgsStorage().entityRepositories.find(r => r.target === repo);
  if (!meta) throw new Error('missing @EntityRepository');
  const extendsRepo = Object.prototype.isPrototypeOf.call(Repository.prototype, repo.prototype);
  if (extendsRepo && !meta.entity) {
    throw new Error(`${repo.name} extends Repository and must pass an entity to @EntityRepository`);
  }
}
assertRepoDecorationConsistent(UserRepo);

Prevention

When it happens

Trigger: Writing `@EntityRepository()` (no entity) on a class that extends `Repository<T>`; refactoring from AbstractRepository to Repository but forgetting to add the entity to the decorator; using a bare @EntityRepository() on a generic Repository subclass for a multi-entity repo.

Common situations: Following a tutorial that used AbstractRepository then switching the base class; copy-paste where the entity argument was dropped; type confusion between Repository (entity-bound) and AbstractRepository (manager-bound).

Related errors


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