twigphp/Twig · error · RuntimeError
Neither the property "%1$s" nor one of the methods…
Error message
Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()", "is%1$s()", "has%1$s()" or "__call()" exist and have public access in class "%2$s".
What it means
Thrown when getAttribute() cannot resolve a property/method on an object: neither the property nor get/is/has-prefixed accessors or __call() exist with public visibility. When strict_variables is enabled (and ignoreStrictCheck is false) this becomes a RuntimeError instead of returning null.
Solutions
- Fix the property name in the template or add a public getter (getFoo/isFoo/hasFoo) to the class
- Verify the object passed into the template context is the intended class
- Check twig strict_variables config; keep it on in dev but ensure templates are correct rather than disabling
- Use the 'defined' test ({{ object.foo is defined }}) when the attribute may legitimately be absent
Example fix
// before
class User { private string $name; }
{{ user.name }}
// after
class User { private string $name; public function getName(): string { return $this->name; } }
{{ user.name }} Defensive patterns
Strategy: type-guard
Validate before calling
if (!method_exists($obj, 'getName') && !property_exists($obj, 'name')) { /* fix before render */ } Type guard
function hasPublicAccessor(object $obj, string $prop): bool { return property_exists($obj, $prop) && (new \ReflectionProperty($obj, $prop))->isPublic() || method_exists($obj, 'get'.ucfirst($prop)); } Try / catch
try { $twig->render($tpl, $ctx); } catch (\Twig\Error\RuntimeError $e) { if (str_starts_with($e->getMessage(), 'Neither the property')) { /* wrong object or missing getter */ } } Prevention
- Provide public getters for all properties used in templates
- Run strict_variables=true in CI to catch template typos
- Use {{ attr is defined }} test for optional attributes
When it happens
Trigger: Accessing {{ object.foo }} or {{ object.foo() }} where the object's class lacks public property foo and public foo()/getFoo()/isFoo()/hasFoo()/__call(); common with typos, private/protected properties, or wrong object passed.
Common situations: Doctrine entities with private properties accessed directly; renamed getters after refactor; strict_variables=true in prod config exposing silent nulls; passing a DTO different from the expected one;magic __get removed in newer framework versions.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Failed to load Twig template
- The "cycle" function expects a non-empty sequence.
- The "random" function cannot pick from an empty sequence or…
- Regexp " " passed to "matches" failed: .
- Trimming side must be "left", "right" or "both".
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/9a25defc85534abc.
Report an issue: GitHub.
Appendix: source
Thrown at src/Extension/CoreExtension.php:1966
} elseif (isset($cache[$class][$lcItem = strtolower($item)])) {
$method = $cache[$class][$lcItem];
} elseif (isset($cache[$class]['__call'])) {
$method = $item;
$call = true;
} else {
if ($isDefinedTest) {
return false;
}
if ($propertyNotAllowedError) {
throw $propertyNotAllowedError;
}
if ($ignoreStrictCheck || !$env->isStrictVariables()) {
return;
}
throw new RuntimeError(\sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()", "is%1$s()", "has%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), $lineno, $source);
}
if ($sandboxed) {
try {
$env->getExtension(SandboxExtension::class)->getChecker()->checkMethodAllowed($object, $method, $lineno, $source);
} catch (SecurityNotAllowedMethodError $e) {
if ($isDefinedTest) {
return false;
}
if ($propertyNotAllowedError) {
throw $propertyNotAllowedError;
}
throw $e;
}
}
View on GitHub (pinned to a414c3a491)