typeorm/typeorm · error · CannotDetermineEntityError

Cannot ${operation}, given value must be instance of entity

Error message

Cannot ${operation}, given value must be instance of entity class, instead object literal is given. Or you must specify an entity target to method call.

What it means

Thrown as `CannotDetermineEntityError` inside `EntityPersistExecutor.execute()` when the entity target cannot be inferred: the passed value is a plain object literal whose `constructor === Object`, and no explicit `target` (entity class) was supplied to the persist call. TypeORM needs an entity class to look up metadata; without it, save/remove/etc. is refused.

Source

Thrown at src/persistence/EntityPersistExecutor.ts:79

        try {
            // collect all operate subjects
            const entities: ObjectLiteral[] = Array.isArray(this.entity)
                ? this.entity
                : [this.entity]
            const chunkSize = this.options?.chunk ?? 0
            const entitiesInChunks =
                chunkSize > 0 ? OrmUtils.chunk(entities, chunkSize) : [entities]

            const buildExecutor = async (
                entities: ObjectLiteral[],
            ): Promise<SubjectExecutor> => {
                const subjects: Subject[] = []

                // create subjects for all entities we received for the persistence
                entities.forEach((entity) => {
                    const entityTarget = this.target ?? entity.constructor
                    if (entityTarget === Object)
                        throw new CannotDetermineEntityError(this.mode)

                    const metadata = this.dataSource
                        .getMetadata(entityTarget)
                        .findInheritanceMetadata(entity)

                    subjects.push(
                        new Subject({
                            metadata,
                            entity: entity,
                            canBeInserted: this.mode === "save",
                            canBeUpdated: this.mode === "save",
                            mustBeRemoved: this.mode === "remove",
                            canBeSoftRemoved: this.mode === "soft-remove",
                            canBeRecovered: this.mode === "recover",
                        }),
                    )
                })

View on GitHub (pinned to 04ff4daedc)

Solutions

  1. Construct an entity instance before saving: `manager.save(Object.assign(new User(), dto))`.
  2. Pass the entity target explicitly as the first argument: `manager.save(User, dto)` or `manager.save(User, [dto1, dto2])`.
  3. When using a repository, ensure the values retain their class prototype (avoid `JSON.parse` / spread that produces plain objects).

Example fix

// before
await dataSource.manager.save({ name: "Alex", email: "a@b.c" })

// after — pass the target explicitly
await dataSource.manager.save(User, { name: "Alex", email: "a@b.c" })
// or construct an instance
const u = Object.assign(new User(), { name: "Alex", email: "a@b.c" })
await dataSource.manager.save(u)
Defensive patterns

Strategy: type-guard

Validate before calling

// Reject plain object literals before persistence
function assertEntityInstance(value: any, target?: Function): void {
  if (!target && value?.constructor === Object) {
    throw new Error("Refusing to persist a plain object literal; pass a target or an instance")
  }
}

Type guard

function isEntityInstance<T>(value: any, target: new () => T): value is T {
  return value instanceof target
}

Try / catch

try {
  await manager.save(value)
} catch (e) {
  if (e instanceof CannotDetermineEntityError) {
    await manager.save(Target, value) // retry with explicit target
  } else throw e
}

Prevention

When it happens

Trigger: `dataSource.manager.save({ name: "x" })` with a plain object and no class; `repository.save([{ id: 1 }])` where elements are object literals; calling `entityManager.persist(target=undefined, plainObject)`; spreading a class instance into a plain object (`{ ...user }`) before saving.

Common situations: Refactoring from class instances to plain DTOs; passing parsed JSON bodies directly to save; using `Object.assign({}, entity)` which strips the prototype; mixing repository-style (`repo.save(plainObj)`) with entityManager-style without a target.

Related errors


AI-assisted analysis of typeorm/typeorm@04ff4daedc (2026-08-03). Data as JSON: /data/errors/f73a514a896ac83e.json. Report an issue: GitHub.