twigphp/Twig · error · SyntaxError

Only "include" tags are allowed within a "sandbox" section.

Error message

Only "include" tags are allowed within a "sandbox" section.

What it means

A {% sandbox %} block may only contain {% include %} tags (whitespace text nodes are ignored). The sandbox exists to evaluate untrusted templates safely, and only includes of sandboxed templates are permitted; any other tag inside is a syntax error.

Solutions

  1. Move all logic into a separate template and inside the sandbox use only '{% include "untrusted.html.twig" %}'
  2. Ensure the included template is registered via sundry/security policy with SandboxExtension enabled
  3. Remove the sandbox wrapper if you don't actually need sandboxing of untrusted includes

Example fix

// before
{% sandbox %}{% set x = 1 %}{{ x }}{% endsandbox %}
// after
{% sandbox %}{% include 'untrusted.html.twig' %}{% endsandbox %}
Defensive patterns

Strategy: validation

Validate before calling

// Only permit include tags inside sandbox blocks
if (preg_match('/\{%-?\s*sandbox\b.*?\{%-?\s*endsandbox/s', $src, $m) && preg_match('/\{%-?\s*(?!include\b|endsandbox)(\w+)/s', $m[0], $bad)) {
    throw new InvalidArgumentException(sprintf('Tag "%s" is not allowed inside a sandbox block.', $bad[1]));
}

Try / catch

try {
    $twig->render($untrustedTemplate);
} catch (SyntaxError $e) {
    // reject untrusted template: only include-in-sandbox templates are accepted
}

Prevention

When it happens

Trigger: Writing '{% sandbox %}{% for x in y %}...{% endfor %}{% endsandbox %}' or placing any tag other than include (e.g. 'set', 'if', raw text output) directly inside a sandbox section; SandboxTokenParser::parse throws when a body node is not an IncludeNode.

Common situations: Assuming {% sandbox %} sandboxes arbitrary template code (it only guards included templates); wrapping existing template snippets in sandbox and forgetting to move their logic into separate templates included via {% include %}.

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/4130f48ff135e0a4. Report an issue: GitHub.

Appendix: source

Thrown at src/TokenParser/SandboxTokenParser.php:53

    {
        $stream = $this->parser->getStream();
        trigger_deprecation('twig/twig', '3.15', \sprintf('The "sandbox" tag is deprecated in "%s" at line %d.', $stream->getSourceContext()->getName(), $token->getLine()));

        $stream->expect(Token::BLOCK_END_TYPE);
        $body = $this->parser->subparse([$this, 'decideBlockEnd'], true);
        $stream->expect(Token::BLOCK_END_TYPE);

        // in a sandbox tag, only include tags are allowed
        if ($body instanceof IncludeNode) {
            $body->setAttribute('sandboxed', true);
        } else {
            foreach ($body as $node) {
                if ($node instanceof TextNode && ctype_space($node->getAttribute('data'))) {
                    continue;
                }

                if (!$node instanceof IncludeNode) {
                    throw new SyntaxError('Only "include" tags are allowed within a "sandbox" section.', $node->getTemplateLine(), $stream->getSourceContext());
                }

                $node->setAttribute('sandboxed', true);
            }
        }

        return new SandboxNode($body, $token->getLine());
    }

    public function decideBlockEnd(Token $token): bool
    {
        return $token->test('endsandbox');
    }

    public function getTag(): string
    {
        return 'sandbox';
    }

View on GitHub (pinned to a414c3a491)