{"record":{"id":"6872d3acdf422edb","repo":"doctrine/orm","slug":"cannot-call-recomputesingleentitychangeset-before","errorCode":null,"errorMessage":"Cannot call recomputeSingleEntityChangeSet before computeChangeSet on an entity.","messagePattern":"Cannot call recomputeSingleEntityChangeSet before computeChangeSet on an entity\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/UnitOfWork.php","lineNumber":1008,"sourceCode":"\n        if (! $class->isInheritanceTypeNone()) {\n            $class = $this->em->getClassMetadata($entity::class);\n        }\n\n        $actualData = [];\n\n        foreach ($class->propertyAccessors as $name => $refProp) {\n            if (\n                ( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity())\n                && ($name !== $class->versionField)\n                && ! $class->isCollectionValuedAssociation($name)\n            ) {\n                $actualData[$name] = $refProp->getValue($entity);\n            }\n        }\n\n        if (! isset($this->originalEntityData[$oid])) {\n            throw new RuntimeException('Cannot call recomputeSingleEntityChangeSet before computeChangeSet on an entity.');\n        }\n\n        $originalData = $this->originalEntityData[$oid];\n        $changeSet    = [];\n\n        foreach ($actualData as $propName => $actualValue) {\n            $orgValue = $originalData[$propName] ?? null;\n\n            if (isset($class->fieldMappings[$propName]->enumType)) {\n                if (is_array($orgValue)) {\n                    foreach ($orgValue as $id => $val) {\n                        if ($val instanceof BackedEnum) {\n                            $orgValue[$id] = $val->value;\n                        }\n                    }\n                } else {\n                    if ($orgValue instanceof BackedEnum) {\n                        $orgValue = $orgValue->value;","sourceCodeStart":990,"sourceCodeEnd":1026,"githubUrl":"https://github.com/doctrine/orm/blob/d9b9ff73016bf598ae07515f97289ce8074e97a5/src/UnitOfWork.php#L990-L1026","documentation":"recomputeSingleEntityChangeSet() diffs an entity's current property values against the 'original data' snapshot the UnitOfWork stored when the entity became managed (during load or computeChangeSets at flush). If originalEntityData for the object id was never set, there is no baseline to diff against, so Doctrine throws instead of producing a wrong change set.","triggerScenarios":"Calling $em->getUnitOfWork()->recomputeSingleEntityChangeSet($classMetadata, $entity) on an entity that was never managed by this EntityManager in a computed state: a NEW entity built in code (persisted but not yet flushed/computed), a DETACHED entity, an entity belonging to a different EntityManager, or any entity after $em->clear()/detach().","commonSituations":"onFlush / lifecycle-listener helper code that mutates entities and recomputes change sets; helper functions called for both freshly constructed and managed entities; listener code surviving an $em->clear() in long-running workers.","solutions":["Guard the call: only recompute when $uow->getEntityState($entity) === UnitOfWork::STATE_MANAGED.","For newly created entities, persist them and let the normal flush compute their insert; do not recompute change sets for them.","If the entity is detached or from another EM, reload it through this EntityManager ($em->find(...)), mutate, then recompute."],"exampleFix":"// before\n$uow = $em->getUnitOfWork();\n$uow->recomputeSingleEntityChangeSet($classMeta, $entity); // throws for unmanaged/new entities\n\n// after\n$uow = $em->getUnitOfWork();\nif ($uow->getEntityState($entity) === UnitOfWork::STATE_MANAGED) {\n    $uow->recomputeSingleEntityChangeSet($classMeta, $entity);\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Narrow to entities the UnitOfWork can diff (managed, with an original-data snapshot)\nfunction isRecomputable(EntityManager $em, object $entity): bool\n{\n    return $em->getUnitOfWork()->getEntityState($entity)\n        === UnitOfWork::STATE_MANAGED;\n}","tryCatchPattern":"// In listeners: recompute only when managed, otherwise let normal persist/flush handle it\n$uow = $em->getUnitOfWork();\nif ($uow->getEntityState($entity) === UnitOfWork::STATE_MANAGED) {\n    $uow->recomputeSingleEntityChangeSet($em->getClassMetadata($entity::class), $entity);\n}","preventionTips":["Treat recomputeSingleEntityChangeSet as an advanced API: only call it from flush-time listeners on managed entities","Never call it for freshly constructed or detached entities - persist and flush, or reload via find()","After em->clear() in long-running workers, reload entities before mutating and recomputing"],"tags":["doctrine-orm","unit-of-work","change-set","entity-state","lifecycle-listener","flush"],"backgroundTag":"orm-unit-of-work-entity-state","analyzedSha":"d9b9ff73016bf598ae07515f97289ce8074e97a5","analyzedAt":"2026-08-21T06:13:15.863Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}