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
- Add the method for that class: $policy->setAllowedMethods([MyClass::class => ['getName', ...]]) or extend the constructor's $allowedMethods array.
- Catch SecurityNotAllowedMethodError in the renderer to log class and method names and adjust the policy.
- Limit what is passed into sandboxed templates to fully allowlisted value objects.
- 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
- Map every class exposed to sandboxes with its allowed methods.
- Use dedicated read-only view-models instead of domain objects.
- Remember macros/namespaces get no sandbox exemption.
- Log blocked calls in staging to discover needed allowlist entries.
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
- Tag " " is not allowed.
- Filter " " is not allowed.
- Function " " is not allowed.
- Test " " is not allowed.
- Calling " " property on a " " object is not allowed.
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)