twigphp/Twig · error · SyntaxError

Calling the "parent" function on a template that does not…

Error message

Calling the "parent" function on a template that does not call "extends" or "use" is forbidden.

What it means

CoreExtension::parseParentFunction additionally requires that the template actually has inheritance. Calling `parent()` inside a block of a template that never calls `{% extends %}` or `{% use %}` is forbidden, because there is no parent implementation to delegate to. Twig throws this SyntaxError at compile time when `$parser->hasInheritance()` is false.

Solutions

  1. Add the appropriate `{% extends 'base.html.twig' %}` (or `{% use '...' %}`) at the top of the template.
  2. If the template should be standalone, replace `{{ parent() }}` with the markup it was meant to inherit or delete the call.
  3. Use `{% extends parent_template %}` dynamically (a variable) if the parent is chosen at runtime — that also registers inheritance.
  4. Review the compile-time SyntaxError source context to confirm which template lacks inheritance.

Example fix

// before (Twig)
{% block title %}{{ parent() }} - App{% endblock %}

// after
{% extends 'base.html.twig' %}
{% block title %}{{ parent() }} - App{% endblock %}
Defensive patterns

Strategy: validation

Validate before calling

// CI lint step (Symfony)
// php bin/console lint:twig templates/ --format=github
// fails the build on 'does not call "extends" or "use"' errors

Try / catch

try {
    $twig->parse($twig->tokenize(new \Twig\Source($templateCode, $name)));
} catch (\Twig\Error\SyntaxError $e) {
    if (str_contains($e->getMessage(), 'does not call "extends" or "use"')) {
        // report the template missing its inheritance declaration
    } else { throw $e; }
}

Prevention

When it happens

Trigger: A template containing `{% block x %}{{ parent() }}{% endblock %}` but with no `{% extends '...' %}` or `{% use '...' %}` tag anywhere in it. The block stack check (error 66) passes, but the inheritance flag is false.

Common situations: Copy-pasting an overriding block (with its parent() call) into a standalone template; removing an extends tag during refactoring while keeping the block body; a template that used to extend a base but was promoted to a top-level entry template.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at src/Extension/CoreExtension.php:2228

            }

            throw $e;
        }

        return ob_get_clean();
    }

    /**
     * @internal
     */
    public static function parseParentFunction(Parser $parser, Node $fakeNode, $args, int $line): AbstractExpression
    {
        if (!$blockName = $parser->peekBlockStack()) {
            throw new SyntaxError('Calling the "parent" function outside of a block is forbidden.', $line, $parser->getStream()->getSourceContext());
        }

        if (!$parser->hasInheritance()) {
            throw new SyntaxError('Calling the "parent" function on a template that does not call "extends" or "use" is forbidden.', $line, $parser->getStream()->getSourceContext());
        }

        return new ParentExpression($blockName, $line);
    }

    /**
     * @internal
     */
    public static function parseBlockFunction(Parser $parser, Node $fakeNode, $args, int $line): AbstractExpression
    {
        $fakeFunction = new TwigFunction('block', static fn ($name, $template = null) => null);
        $args = (new CallableArgumentsExtractor($fakeNode, $fakeFunction))->extractArguments($args);

        return new BlockReferenceExpression($args[0], $args[1] ?? null, $line);
    }

    /**
     * @internal

View on GitHub (pinned to a414c3a491)