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
- Pass the entity to the decorator: `@EntityRepository(User)` on Repository-extending classes.
- If the repo intentionally serves multiple entities, extend `AbstractRepository` instead and use the injected `this.manager`.
- 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
- Rule: extends Repository<Entity> ⇒ @EntityRepository(Entity).
- Rule: extends AbstractRepository ⇒ @EntityRepository() is fine.
- Audit decorator arguments when switching the base class.
- Add a unit test that asserts every custom repo decoration is consistent.
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
- Custom repository ${repository.name} was not found. Did you
- Invalid prefix option given for ${this.entityMetadata.target
- Transaction method requires callback in second parameter if
- Column "${columnName}" was not found in table "${metadata.na
- You must provide selection conditions in order to find a sin
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/2c02265ec052c947.
Report an issue: GitHub.