twigphp/Twig · error · RuntimeError

Accessing \Twig\Template attributes is forbidden.

Error message

Accessing \Twig\Template attributes is forbidden.

What it means

CoreExtension::getAttribute() forbids accessing attributes or calling methods on a \Twig\Template instance itself. This guards template internals (blocks, sources, env) from being inspected or mutated from inside templates.

Solutions

  1. Remove the Template instance from the template context; pass plain data instead
  2. If you loaded a template by accident (env->load(...)), render it or use ->renderBlock() server-side rather than passing the object
  3. Unwrap the value: pass $template->getSourceContext() or rendered output instead of the object

Example fix

// before (PHP controller)
return $this->render('base.html.twig', ['tpl' => $template]);

// after
return $this->render('base.html.twig', ['content' => $template->render([])]);
Defensive patterns

Strategy: type-guard

Validate before calling

foreach ($context as $k => $v) { if ($v instanceof \Twig\Template) { throw new \RuntimeException("Context key '$k' holds a Template object"); } }

Type guard

function isTwigTemplate($v): bool { return $v instanceof \Twig\Template; }

Try / catch

try { $twig->render($tpl, $ctx); } catch (\Twig\Error\RuntimeError $e) { if (str_contains($e->getMessage(), 'attributes is forbidden')) { /* remove Template from context */ } }

Prevention

When it happens

Trigger: A template variable holds a Twig\Template object (or a template is passed as context value) and the template does {{ template.someAttr }} or {{ template.someMethod() }}.

Common situations: Passing a Template object into the context by mistake (e.g. from a custom extension returning $this or a loaded template), or iterating over template instances; experimental/internal code doing reflection-ish access from templates.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13). Data as JSON: /api/errors/1ac72b01dd0d58bb. Report an issue: GitHub.

Appendix: source

Thrown at src/Extension/CoreExtension.php:1850

            }

            if ($ignoreStrictCheck || !$env->isStrictVariables()) {
                return;
            }

            if (null === $object) {
                $message = \sprintf('Impossible to invoke a method ("%s") on a null variable.', $item);
            } elseif (\is_array($object)) {
                $message = \sprintf('Impossible to invoke a method ("%s") on a sequence/mapping.', $item);
            } else {
                $message = \sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, get_debug_type($object), $object);
            }

            throw new RuntimeError($message, $lineno, $source);
        }

        if ($object instanceof Template) {
            throw new RuntimeError('Accessing \Twig\Template attributes is forbidden.', $lineno, $source);
        }

        // object property
        if (Template::METHOD_CALL !== $type) {
            if ($sandboxed) {
                try {
                    $env->getExtension(SandboxExtension::class)->getChecker()->checkPropertyAllowed($object, $item, $lineno, $source);
                } catch (SecurityNotAllowedPropertyError $propertyNotAllowedError) {
                    goto methodCheck;
                }
            }

            static $propertyCheckers = [];

            if (isset($object->$item)
                || ($propertyCheckers[$object::class][$item] ??= self::getPropertyChecker($object::class, $item))($object, $item)
            ) {
                if ($isDefinedTest) {

View on GitHub (pinned to a414c3a491)