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

  1. Fix the property name in the template or add a public getter (getFoo/isFoo/hasFoo) to the class
  2. Verify the object passed into the template context is the intended class
  3. Check twig strict_variables config; keep it on in dev but ensure templates are correct rather than disabling
  4. 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

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


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)