rectorphp/rector · error · MissingPrivatePropertyException
Property "$%s" was not found in "%s" class
Error message
Property "$%s" was not found in "%s" class
What it means
PrivatesAccessor reflectively resolves a property for read/write: first on get_class($object), then via get_parent_class() up the hierarchy. If neither level declares it, the search is exhausted and MissingPrivatePropertyException('Property "$%s" was not found in "%s" class') is thrown with the property name and concrete class.
Source
Thrown at src/Util/Reflection/PrivatesAccessor.php:82
private function resolvePropertyReflection(object $object, string $propertyName): ReflectionProperty
{
if (property_exists($object, $propertyName)) {
$reflection = new ReflectionProperty($object, $propertyName);
if (\PHP_VERSION_ID < 80100) {
$reflection->setAccessible(\true);
}
return $reflection;
}
$parentClass = get_parent_class($object);
if ($parentClass !== \false) {
$reflection = new ReflectionProperty($parentClass, $propertyName);
if (\PHP_VERSION_ID < 80100) {
$reflection->setAccessible(\true);
}
return $reflection;
}
$errorMessage = sprintf('Property "$%s" was not found in "%s" class', $propertyName, get_class($object));
throw new MissingPrivatePropertyException($errorMessage);
}
}
View on GitHub (pinned to 408fcb0ff1)
Solutions
- Verify the exact name and casing with (new ReflectionClass($object))->getProperty(...) or var_dump(get_class_vars(get_class($object)))
- Update the accessor call to the renamed property after upgrading the library
- If the state moved to another class in the hierarchy, target that class explicitly instead of the instance's root
Example fix
// before $value = $privatesAccessor->getPrivateProperty($nodeFactory, 'nameResolver'); // renamed upstream // after $value = $privatesAccessor->getPrivateProperty($nodeFactory, 'nameResolverFactory');
Defensive patterns
Strategy: type-guard
Type guard
function privatePropertyExists(object $object, string $propertyName): bool
{
$class = get_class($object);
do {
if (property_exists($class, $propertyName)) {
return true;
}
$class = get_parent_class($class) ?: null;
} while ($class !== null);
return false;
} Try / catch
try {
$value = $privatesAccessor->getPrivateProperty($object, $propertyName);
} catch (\Rector\Exception\Util\MissingPrivatePropertyException $e) {
// typo or upstream rename: log and skip the assertion rather than fail hard
$logger->warning($e->getMessage());
return null;
} Prevention
- Prefer public test hooks/mother objects over reflecting private state when you control the class
- After each Rector upgrade, grep test fixtures for accessor calls and reconcile renamed internals
- Assert privatePropertyExists() before getPrivateProperty() to fail with a clearer message
When it happens
Trigger: Calling PrivatesAccessor->getPrivateProperty()/setPrivateProperty() (or the reflection resolver directly) with a misspelled or case-mismatched property name, or against a class whose property was renamed/removed in an upstream release.
Common situations: Rector upgrade tests that poke private state via PrivatesAccessor and break when internals rename a field; typo'd names after refactoring; expecting a property that only exists on a sibling, not the parent chain.
Related errors
- Fixture file and input file cannot be the same:
- "%s" rule is deprecated, as turning a docblock type into a r
- "%s" rule is deprecated, as risky. The "??" and "?:" operato
- "%s" is deprecated as depends on context and personal prefer
- "%s" rule is deprecated, as it is a personal preference that
AI-assisted analysis of rectorphp/rector@408fcb0ff1 (2026-08-21).
Data as JSON: /api/errors/b23a663f8baf9299.
Report an issue: GitHub.