{"record":{"id":"ea0d612b5d85aa57","repo":"doctrine/instantiator","slug":"an-exception-was-raised-while-trying-to-instantiat","errorCode":null,"errorMessage":"An exception was raised while trying to instantiate an instance of \"%s\" via un-serialization","messagePattern":"An exception was raised while trying to instantiate an instance of \"(.+?)\" via un-serialization","errorType":"exception","errorClass":"Doctrine\\Instantiator\\Exception\\UnexpectedValueException","httpStatus":null,"severity":"error","filePath":"src/Exception/UnexpectedValueException.php","lineNumber":29,"sourceCode":"use function sprintf;\n\n/**\n * Exception for given parameters causing invalid/unexpected state on instantiation\n */\nclass UnexpectedValueException extends BaseUnexpectedValueException implements ExceptionInterface\n{\n    /**\n     * @phpstan-param ReflectionClass<T> $reflectionClass\n     *\n     * @template T of object\n     */\n    public static function fromSerializationTriggeredException(\n        ReflectionClass $reflectionClass,\n        Exception $exception,\n    ): self {\n        return new self(\n            sprintf(\n                'An exception was raised while trying to instantiate an instance of \"%s\" via un-serialization',\n                $reflectionClass->getName(),\n            ),\n            0,\n            $exception,\n        );\n    }\n\n    /**\n     * @phpstan-param ReflectionClass<T> $reflectionClass\n     *\n     * @template T of object\n     */\n    public static function fromUncleanUnSerialization(\n        ReflectionClass $reflectionClass,\n        string $errorString,\n        int $errorCode,\n        string $errorFile,\n        int $errorLine,","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/doctrine/instantiator/blob/cbb879d6eea7ce605d95f4c455679df73ee682ea/src/Exception/UnexpectedValueException.php#L11-L47","documentation":"When a class cannot be created via ReflectionClass::newInstanceWithoutConstructor() (final classes with internal ancestors, src/Instantiator.php:213-216), the instantiator falls back to a synthetic serialized payload like 'C:12:\"ClassName\":0:{}' and probes unserialize() with it (checkIfUnSerializationIsSupported(), src/Instantiator.php:167-190). If that probe unserialize() throws an Exception, fromSerializationTriggeredException() wraps it with the class name and chains the original as previous. The real cause is always in getPrevious(): userland code that runs during unserialization (Serializable::unserialize(), __wakeup(), __unserialize()) threw on the empty probe payload.","triggerScenarios":"instantiate() hits the unserialization fallback path and the probe unserialize() throws instead of raising a PHP warning: typically a class implementing Serializable whose unserialize('') throws (empty-string validation, argument checks), or a __wakeup()/__unserialize() that throws when the object state is empty. The catch at src/Instantiator.php:203-204 converts the thrown Exception into this wrapper.","commonSituations":"Legacy classes implementing the old Serializable interface with strict payload validation that rejects the empty payload the library probes with; __wakeup() implementations that assert preconditions on properties the synthetic payload never sets; final classes extending internal SPL/PDO classes forced onto the unserialize path; code migrated from __wakeup to __unserialize that now throws where it previously warned.","solutions":["Catch the exception and inspect getPrevious() — it holds the original exception thrown inside unserialize(), which names the actual faulting code.","Make Serializable::unserialize() / __wakeup() / __unserialize() tolerate the empty payload: return early on '' or empty arrays instead of throwing.","Prefer the modern __serialize()/__unserialize() pair over the legacy Serializable interface when you control the class.","If the throwing behavior cannot be changed, construct the object yourself (new $className(...) or ReflectionClass::newInstanceWithoutConstructor() when the class allows it) instead of using this instantiator for that type."],"exampleFix":"// before\nclass Money implements \\Serializable\n{\n    public function unserialize($data): void\n    {\n        if ($data === '') {\n            throw new \\InvalidArgumentException('empty payload'); // breaks the Instantiator probe\n        }\n        // ...\n    }\n}\n\n// after: tolerate the empty payload used by the instantiation probe\npublic function unserialize($data): void\n{\n    if ($data === '') {\n        return;\n    }\n    // ...\n}","handlingStrategy":"try-catch","validationCode":"$reflection = new ReflectionClass($className);\n\nif ($reflection->isSubclassOf(Serializable::class)\n    || $reflection->hasMethod('__wakeup')\n    || $reflection->hasMethod('__unserialize')\n) {\n    // the unserialization probe will invoke this code with an empty payload:\n    // make sure it cannot throw before relying on Instantiator\n    $instance = $reflection->newInstanceWithoutConstructor();\n} else {\n    $instance = (new Instantiator())->instantiate($className);\n}","typeGuard":"function isSafeForUnserializationProbe(string $className): bool\n{\n    $r = new ReflectionClass($className);\n\n    return ! $r->isSubclassOf(Serializable::class)\n        && ! $r->hasMethod('__wakeup')\n        && ! $r->hasMethod('__unserialize');\n}","tryCatchPattern":"use Doctrine\\Instantiator\\Exception\\UnexpectedValueException;\n\ntry {\n    $instance = $instantiator->instantiate($className);\n} catch (UnexpectedValueException $e) {\n    $rootCause = $e->getPrevious(); // the exception thrown inside unserialize()\n    // log $rootCause for diagnosis, then fall back to explicit construction\n    return new $className(...$constructorArgs);\n}","preventionTips":["Never throw from Serializable::unserialize() on an empty payload — return early instead.","Prefer __serialize()/__unserialize() over the legacy Serializable interface.","Keep __wakeup()/__unserialize() side-effect free and tolerant of empty object state.","Avoid extending internal final classes when you need constructor-less instantiation."],"tags":["php","unserialization","serializable","wakeup","doctrine-instantiator"],"backgroundTag":"unserialize-threw-exception","analyzedSha":"cbb879d6eea7ce605d95f4c455679df73ee682ea","analyzedAt":"2026-08-21T03:06:19.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}