doctrine/instantiator · error · Doctrine\Instantiator\Exception\UnexpectedValueException
Could not produce an instance of "%s" via un-serialization,
Error message
Could not produce an instance of "%s" via un-serialization, since an error was triggered in file "%s" at line "%d"
What it means
During the unserialization fallback, the instantiator installs a temporary error handler around a probe unserialize() (src/Instantiator.php:169-179). Any PHP notice/warning raised during that probe — as opposed to a thrown Exception — is converted by fromUncleanUnSerialization() into this message, which reports the file and line where the PHP error fired, with the raw warning text and code chained in the previous exception. The cause is code executed during unserialization (Serializable::unserialize(), __wakeup(), __unserialize()) or PHP itself emitting diagnostics on the synthetic empty payload.
Source
Thrown at src/Exception/UnexpectedValueException.php:51
$exception,
);
}
/**
* @phpstan-param ReflectionClass<T> $reflectionClass
*
* @template T of object
*/
public static function fromUncleanUnSerialization(
ReflectionClass $reflectionClass,
string $errorString,
int $errorCode,
string $errorFile,
int $errorLine,
): self {
return new self(
sprintf(
'Could not produce an instance of "%s" via un-serialization, since an error was triggered '
. 'in file "%s" at line "%d"',
$reflectionClass->getName(),
$errorFile,
$errorLine,
),
0,
new Exception($errorString, $errorCode),
);
}
}
View on GitHub (pinned to cbb879d6ee)
Solutions
- Read the message: it names the exact file and line of the PHP error, and getPrevious() carries the raw warning string and error code — fix the code at that location first.
- Make __wakeup()/Serializable::unserialize()/__unserialize() safe for an empty payload: null-coalesce property accesses, guard missing keys, suppress side effects on empty state.
- Avoid extending internal serializable classes (ArrayObject and friends) when you rely on constructor-less instantiation; wrap them instead of extending.
- If the warning source cannot be fixed, instantiate that specific class via new or reflection yourself and keep it out of the instantiator's reach.
Example fix
// before
class Snapshot
{
public function __wakeup(): void
{
// notice on the empty synthetic payload during the probe:
// "Undefined index: hydrated_at" => fromUncleanUnSerialization()
$this->hydratedAt = $this->meta['hydrated_at'];
}
}
// after
class Snapshot
{
public function __wakeup(): void
{
$this->hydratedAt = $this->meta['hydrated_at'] ?? null;
}
} Defensive patterns
Strategy: try-catch
Validate before calling
$reflection = new ReflectionClass($className);
// classes with internal ancestors go through the unserialize probe and may raise PHP warnings
$hasInternalAncestors = false;
for ($r = $reflection; $r !== false; $r = $r->getParentClass()) {
if ($r->isInternal()) {
$hasInternalAncestors = true;
break;
}
}
if ($hasInternalAncestors && $reflection->isFinal()) {
// the synthetic unserialize payload may trigger warnings: instantiate explicitly instead
return $reflection->newInstanceWithoutConstructor();
}
return (new Instantiator())->instantiate($className); Type guard
function emitsNoDiagnosticsDuringWakeup(string $className): bool
{
$r = new ReflectionClass($className);
return ! $r->hasMethod('__wakeup')
&& ! $r->hasMethod('__unserialize')
&& ! $r->isSubclassOf(Serializable::class);
} Try / catch
use Doctrine\Instantiator\Exception\UnexpectedValueException;
try {
$instance = $instantiator->instantiate($className);
} catch (UnexpectedValueException $e) {
// message names the file/line of the PHP warning; getPrevious() holds the raw warning text
$warning = $e->getPrevious();
error_log(sprintf('Instantiator probe warning in %s: %s', $className, $warning?->getMessage()));
return new $className(...$constructorArgs);
} Prevention
- Write __wakeup()/__unserialize() code that cannot raise notices on empty state: null-coalesce every property access.
- Do not extend internal serializable classes (ArrayObject, ArrayIterator, SPL collections) if you rely on constructor-less instantiation — wrap them instead.
- Run test suites with error_reporting(E_ALL) converted to exceptions so probe-hostile wakeup code fails during CI, not in production.
- Check the chained previous exception for the exact warning text and code before assuming the instantiator is at fault.
When it happens
Trigger: instantiate() takes the unserialize fallback and the probe raises a PHP error that the handler at src/Instantiator.php:169 captures: a __wakeup() reading an undefined index/property on the empty synthetic payload, a deprecation notice triggered inside unserialize(), or unserialize() itself warning about the payload for classes with internal ancestors (e.g. ArrayObject/ArrayIterator subclasses with 'Erroneous data format for class').
Common situations: Subclasses of internal serializable SPL classes (ArrayObject, ArrayIterator, SplStack) whose synthetic payload is not valid for the internal parent; __wakeup() implementations that dereference keys the empty payload never set; code emitting deprecation notices under newer PHP versions during unserialization; noisy autoloaders or custom error-to-exception converters that emit diagnostics while the probe runs.
Related errors
- An exception was raised while trying to instantiate an insta
- The provided type "%s" is an interface, and cannot be instan
- The provided type "%s" is a trait, and cannot be instantiate
- The provided class "%s" does not exist
- The provided class "%s" is abstract, and cannot be instantia
AI-assisted analysis of doctrine/instantiator@cbb879d6ee (2026-08-21).
Data as JSON: /api/errors/0ed1b28fdd1d2288.
Report an issue: GitHub.