doctrine/orm · error · UnexpectedValueException
Unexpected entity state: %s. %s
Error message
Unexpected entity state: %s. %s
What it means
UnitOfWork::doPersist switches over the entity's computed state (STATE_MANAGED, STATE_NEW, STATE_REMOVED each have explicit handling, STATE_DETACHED throws a dedicated exception). This default arm fires only when the state value falls outside all known constants - an internal invariant break rather than a user input problem. The message includes the numeric state and a string representation of the entity for diagnosis.
Source
Thrown at src/UnitOfWork.php:1849
case self::STATE_REMOVED:
// Entity becomes managed again
unset($this->entityDeletions[$oid]);
$this->addToIdentityMap($entity);
$this->entityStates[$oid] = self::STATE_MANAGED;
if ($class->isChangeTrackingDeferredExplicit()) {
$this->scheduleForDirtyCheck($entity);
}
break;
case self::STATE_DETACHED:
// Can actually not happen right now since we assume STATE_NEW.
throw ORMInvalidArgumentException::detachedEntityCannot($entity, 'persisted');
default:
throw new UnexpectedValueException(sprintf(
'Unexpected entity state: %s. %s',
$entityState,
self::objToStr($entity),
));
}
$this->cascadePersist($entity, $visited);
}
/**
* Deletes an entity as part of the current unit of work.
*/
public function remove(object $entity): void
{
$visited = [];
$this->doRemove($entity, $visited);
}View on GitHub (pinned to d9b9ff7301)
Solutions
- Check $uow->getEntityState($entity) before persisting and handle non-standard/detached states explicitly (e.g. merge or reload instead of persist).
- Verify only one version of doctrine/orm is loaded: composer show doctrine/orm and check for duplicate vendor copies or phar bundling.
- Remove code that subclasses or reflects into UnitOfWork internals, or that serializes/clones the EntityManager.
Defensive patterns
Strategy: validation
Validate before calling
// Validate the state is one Doctrine handles before persisting
$state = $em->getUnitOfWork()->getEntityState($entity);
if (! in_array($state, [UnitOfWork::STATE_NEW, UnitOfWork::STATE_MANAGED, UnitOfWork::STATE_REMOVED], true)) {
throw new InvalidArgumentException('Cannot persist entity in state ' . $state); // includes DETACHED: merge/find first
}
$em->persist($entity); Prevention
- Never serialize or clone an EntityManager/UnitOfWork
- Keep exactly one doctrine/orm version in the dependency tree (composer show doctrine/orm)
- Do not subclass or reflect into UnitOfWork internals
When it happens
Trigger: $em->persist($entity) when UnitOfWork::getEntityState() yields an unexpected value: custom UnitOfWork subclasses or reflection tampering with internal state maps, an EntityManager corrupted by serialization/cloning of internal objects, or doctrine/orm classes from two different versions loaded in the same process.
Common situations: Essentially never in normal usage; seen with duplicated composer dependencies/phar classmaps loading mixed ORM versions, extensions subclassing UnitOfWork internals, or diagnostics tooling serializing the EntityManager.
Related errors
- Cannot call recomputeSingleEntityChangeSet before computeCha
- Dirty entity can not be scheduled for insertion.
- Commit failed
- No persister found for entity.
- Uninitialized result set mapping.
AI-assisted analysis of doctrine/orm@d9b9ff7301 (2026-08-21).
Data as JSON: /api/errors/fc2735511e405dba.
Report an issue: GitHub.