twigphp/Twig · error · SecurityNotAllowedMethodError

Calling " " method on a " " object is not allowed.

Error message

Calling "%s" method on a "%s" object is not allowed.

What it means

checkMethodAllowed() throws SecurityNotAllowedMethodError when sandboxed code calls a method on an object whose class is not covered by any allowlisted class/method pair in $allowedMethods. The sandbox calls this check before any method invocation on objects passed into the template.

Solutions

  1. Add the method for that class: $policy->setAllowedMethods([MyClass::class => ['getName', ...]]) or extend the constructor's $allowedMethods array.
  2. Catch SecurityNotAllowedMethodError in the renderer to log class and method names and adjust the policy.
  3. Limit what is passed into sandboxed templates to fully allowlisted value objects.
  4. Audit macro templates too — they get the same (or stricter) sandbox checks.

Example fix

// before
 $policy = new SecurityPolicy($tags, $filters, [], [], []); // Foo::bar blocked
// after
 $policy->setAllowedMethods([Foo::class => ['bar', 'getBaz']]);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!in_array($method, $policy->getAllowedMethods()[$obj::class] ?? [], true)) {
    // would throw; extend allowlist or use a view-model
}

Type guard

function methodAllowed(object $obj, string $method, array $allowedMethods): bool {
    foreach ($allowedMethods[$obj::class] ?? [] as $rule) {
        if ($rule === $method || str_starts_with($method, $rule)) return true;
    }
    return false;
}

Try / catch

try {
    $html = $twig->render($tpl, ['model' => $obj]);
} catch (\Twig\Sandbox\SecurityNotAllowedMethodError $e) {
    $logger->warning('Sandbox blocked method', ['class' => $e->getClassName(), 'method' => $e->getMethodName()]);
}

Prevention

When it happens

Trigger: Inside a sandbox, a template (or macro, as in testMacroNamespaceDoesNotBenefitFromTheTemplateSandboxExemption) invokes e.g. $obj->getName() where 'getName' is not listed for $obj's class in the policy's allowed methods map; passing a new object type into the sandbox without updating the policy.

Common situations: Macros/namespaces failing to inherit looser rules from the outer template; policies written for one DTO reused with new object types; adding getters to a class without extending the whitelist.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at src/Sandbox/SecurityPolicy.php:164

    public function checkMethodAllowed($obj, $method): void
    {
        if ($obj instanceof Template || $obj instanceof Markup) {
            return;
        }

        $allowed = false;
        $method = strtolower($method);
        foreach ($this->allowedMethods as $class => $methods) {
            if ($obj instanceof $class && \in_array($method, $methods, true)) {
                $allowed = true;
                break;
            }
        }

        if (!$allowed) {
            $class = $obj::class;
            throw new SecurityNotAllowedMethodError(\sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, $class), $class, $method);
        }
    }

    public function checkPropertyAllowed($obj, $property): void
    {
        $allowed = false;
        foreach ($this->allowedProperties as $class => $properties) {
            if ($obj instanceof $class && \in_array($property, \is_array($properties) ? $properties : [$properties], true)) {
                $allowed = true;
                break;
            }
        }

        if (!$allowed) {
            $class = $obj::class;
            throw new SecurityNotAllowedPropertyError(\sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, $class), $class, $property);
        }
    }

View on GitHub (pinned to a414c3a491)