craft-templatecomments icon indicating copy to clipboard operation
craft-templatecomments copied to clipboard

Error with Template Comments + Craft 5 / Twig 3.15 when using Author Toolbar plugin > search option

Open wmdhosting opened this issue 4 months ago • 9 comments

When Template Comments is enabled on a Craft CMS 5 site, any request that renders the Author Toolbar search template throws:

Error: Typed property Twig\Parser::$env must not be accessed before initialization

If I disable Template Comments, the error disappears and Author Toolbar search works normally again.

It looks like there is a compatibility issue between TemplateCommentsParser and Twig 3.15’s Twig\Parser, specifically when Twig\TokenParser\GuardTokenParser calls $this->parser->getEnvironment().

Environment

Craft CMS: 5.8.19

Twig: 3.15.x

PHP: 8.3

Template Comments: 5.0.4 (latest at the moment)

Author Toolbar: (https://plugins.craftcms.com/author-toolbar?craft5)

Steps to reproduce

Install / update Craft CMS and Twig to versions above.

Install and enable:

Template Comments

Author Toolbar

In the CP / frontend, trigger Author Toolbar search endpoint: actions/author-toolbar/search/get-search-results-html

Observe the error.

Actual behavior

The request crashes with:

Error: Typed property Twig\Parser::$env must not be accessed before initialization in vendor/twig/twig/src/Parser.php:60

Top of stack trace:

  1. Twig\Parser::getEnvironment()
  2. Twig\TokenParser\GuardTokenParser::parse()
  3. nystudio107\templatecomments\web\twig\TemplateCommentsParser::subparse() ...
  4. Twig\Environment::loadTemplate('_TwigTemplate...', 'author-toolbar/requests/_search...')
  5. Twig\Environment::load('author-toolbar/requests/_search...')
  6. craft\web\View::renderTemplate('author-toolbar/requests/_search...', [])

Full stack trace (for reference):

Error
Typed property Twig\Parser::$env must not be accessed before initialization

    1. in /home/devkorisnik/vendor/twig/twig/src/Parser.php at line 60
    51525354555657585960616263646566676869

        private $ignoreUnknownTwigCallables = false;
     
        public function __construct(
            private Environment $env,
        ) {
        }
     
        public function getEnvironment(): Environment
        {
            return $this->env;
        }
     
        public function getVarName(): string
        {
            trigger_deprecation('twig/twig', '3.15', 'The "%s()" method is deprecated.', __METHOD__);
     
            return \sprintf('__internal_parse_%d', $this->varNameSalt++);
        }
     

    2. in /home/devkorisnik/vendor/twig/twig/src/TokenParser/GuardTokenParser.php at line 36 – [Twig\Parser::getEnvironment](http://twig.sensiolabs.org/api/2.x/Twig/Parser.html#method_getEnvironment)()
    30313233343536373839404142

                throw new SyntaxError(\sprintf('Supported guard types are function, filter and test, "%s" given.', $typeToken->getValue()), $typeToken->getLine(), $stream->getSourceContext());
            }
            $method = 'get'.$typeToken->getValue();
     
            $nameToken = $stream->expect(Token::NAME_TYPE);
     
            $exists = null !== $this->parser->getEnvironment()->$method($nameToken->getValue());
     
            $stream->expect(Token::BLOCK_END_TYPE);
            if ($exists) {
                $body = $this->parser->subparse([$this, 'decideGuardFork']);
            } else {
                $body = new EmptyNode();

    3. in /home/devkorisnik/vendor/nystudio107/craft-templatecomments/src/web/twig/TemplateCommentsParser.php at line 243 – [Twig\TokenParser\GuardTokenParser::parse](http://twig.sensiolabs.org/api/2.x/Twig/TokenParser/GuardTokenParser.html#method_parse)(Twig\Token)
    237238239240241242243244245246247248249

                            throw $e;
                        }
     
                        $this->stream->next();
     
                        $subparser->setParser($this);
                        $node = $subparser->parse($token);
                        if (!$node) {
                            trigger_deprecation('twig/twig', '3.12', 'Returning "null" from "%s" is deprecated and forbidden by "TokenParserInterface".', $subparser::class);
                        } else {
                            $node->setNodeTag($subparser->getTag());
                            $rv[] = $node;
                        }

    4. in /home/devkorisnik/vendor/twig/twig/src/TokenParser/IfTokenParser.php at line 42 – nystudio107\templatecomments\web\twig\TemplateCommentsParser::subparse([Twig\TokenParser\IfTokenParser, 'decideIfFork'])
    36373839404142434445464748

        public function parse(Token $token): Node
        {
            $lineno = $token->getLine();
            $expr = $this->parser->getExpressionParser()->parseExpression();
            $stream = $this->parser->getStream();
            $stream->expect(Token::BLOCK_END_TYPE);
            $body = $this->parser->subparse([$this, 'decideIfFork']);
            $tests = [$expr, $body];
            $else = null;
     
            $end = false;
            while (!$end) {
                switch ($stream->next()->getValue()) {

    5. in /home/devkorisnik/vendor/nystudio107/craft-templatecomments/src/web/twig/TemplateCommentsParser.php at line 243 – [Twig\TokenParser\IfTokenParser::parse](http://twig.sensiolabs.org/api/2.x/Twig/TokenParser/IfTokenParser.html#method_parse)(Twig\Token)
    237238239240241242243244245246247248249

                            throw $e;
                        }
     
                        $this->stream->next();
     
                        $subparser->setParser($this);
                        $node = $subparser->parse($token);
                        if (!$node) {
                            trigger_deprecation('twig/twig', '3.12', 'Returning "null" from "%s" is deprecated and forbidden by "TokenParserInterface".', $subparser::class);
                        } else {
                            $node->setNodeTag($subparser->getTag());
                            $rv[] = $node;
                        }

    6. in /home/devkorisnik/vendor/twig/twig/src/TokenParser/ForTokenParser.php at line 42 – nystudio107\templatecomments\web\twig\TemplateCommentsParser::subparse([Twig\TokenParser\ForTokenParser, 'decideForFork'])
    36373839404142434445464748

            $stream = $this->parser->getStream();
            $targets = $this->parser->getExpressionParser()->parseAssignmentExpression();
            $stream->expect(Token::OPERATOR_TYPE, 'in');
            $seq = $this->parser->getExpressionParser()->parseExpression();
     
            $stream->expect(Token::BLOCK_END_TYPE);
            $body = $this->parser->subparse([$this, 'decideForFork']);
            if ('else' == $stream->next()->getValue()) {
                $stream->expect(Token::BLOCK_END_TYPE);
                $else = $this->parser->subparse([$this, 'decideForEnd'], true);
            } else {
                $else = null;
            }

    7. in /home/devkorisnik/vendor/nystudio107/craft-templatecomments/src/web/twig/TemplateCommentsParser.php at line 243 – [Twig\TokenParser\ForTokenParser::parse](http://twig.sensiolabs.org/api/2.x/Twig/TokenParser/ForTokenParser.html#method_parse)(Twig\Token)
    237238239240241242243244245246247248249

                            throw $e;
                        }
     
                        $this->stream->next();
     
                        $subparser->setParser($this);
                        $node = $subparser->parse($token);
                        if (!$node) {
                            trigger_deprecation('twig/twig', '3.12', 'Returning "null" from "%s" is deprecated and forbidden by "TokenParserInterface".', $subparser::class);
                        } else {
                            $node->setNodeTag($subparser->getTag());
                            $rv[] = $node;
                        }

    8. in /home/devkorisnik/vendor/twig/twig/src/TokenParser/IfTokenParser.php at line 42 – nystudio107\templatecomments\web\twig\TemplateCommentsParser::subparse([Twig\TokenParser\IfTokenParser, 'decideIfFork'])
    36373839404142434445464748

        public function parse(Token $token): Node
        {
            $lineno = $token->getLine();
            $expr = $this->parser->getExpressionParser()->parseExpression();
            $stream = $this->parser->getStream();
            $stream->expect(Token::BLOCK_END_TYPE);
            $body = $this->parser->subparse([$this, 'decideIfFork']);
            $tests = [$expr, $body];
            $else = null;
     
            $end = false;
            while (!$end) {
                switch ($stream->next()->getValue()) {

    9. in /home/devkorisnik/vendor/nystudio107/craft-templatecomments/src/web/twig/TemplateCommentsParser.php at line 243 – [Twig\TokenParser\IfTokenParser::parse](http://twig.sensiolabs.org/api/2.x/Twig/TokenParser/IfTokenParser.html#method_parse)(Twig\Token)
    237238239240241242243244245246247248249

                            throw $e;
                        }
     
                        $this->stream->next();
     
                        $subparser->setParser($this);
                        $node = $subparser->parse($token);
                        if (!$node) {
                            trigger_deprecation('twig/twig', '3.12', 'Returning "null" from "%s" is deprecated and forbidden by "TokenParserInterface".', $subparser::class);
                        } else {
                            $node->setNodeTag($subparser->getTag());
                            $rv[] = $node;
                        }

    10. in /home/devkorisnik/vendor/twig/twig/src/TokenParser/ForTokenParser.php at line 42 – nystudio107\templatecomments\web\twig\TemplateCommentsParser::subparse([Twig\TokenParser\ForTokenParser, 'decideForFork'])
    36373839404142434445464748

            $stream = $this->parser->getStream();
            $targets = $this->parser->getExpressionParser()->parseAssignmentExpression();
            $stream->expect(Token::OPERATOR_TYPE, 'in');
            $seq = $this->parser->getExpressionParser()->parseExpression();
     
            $stream->expect(Token::BLOCK_END_TYPE);
            $body = $this->parser->subparse([$this, 'decideForFork']);
            if ('else' == $stream->next()->getValue()) {
                $stream->expect(Token::BLOCK_END_TYPE);
                $else = $this->parser->subparse([$this, 'decideForEnd'], true);
            } else {
                $else = null;
            }

    11. in /home/devkorisnik/vendor/nystudio107/craft-templatecomments/src/web/twig/TemplateCommentsParser.php at line 243 – [Twig\TokenParser\ForTokenParser::parse](http://twig.sensiolabs.org/api/2.x/Twig/TokenParser/ForTokenParser.html#method_parse)(Twig\Token)
    237238239240241242243244245246247248249

                            throw $e;
                        }
     
                        $this->stream->next();
     
                        $subparser->setParser($this);
                        $node = $subparser->parse($token);
                        if (!$node) {
                            trigger_deprecation('twig/twig', '3.12', 'Returning "null" from "%s" is deprecated and forbidden by "TokenParserInterface".', $subparser::class);
                        } else {
                            $node->setNodeTag($subparser->getTag());
                            $rv[] = $node;
                        }

    12. in /home/devkorisnik/vendor/twig/twig/src/TokenParser/IfTokenParser.php at line 42 – nystudio107\templatecomments\web\twig\TemplateCommentsParser::subparse([Twig\TokenParser\IfTokenParser, 'decideIfFork'])
    36373839404142434445464748

        public function parse(Token $token): Node
        {
            $lineno = $token->getLine();
            $expr = $this->parser->getExpressionParser()->parseExpression();
            $stream = $this->parser->getStream();
            $stream->expect(Token::BLOCK_END_TYPE);
            $body = $this->parser->subparse([$this, 'decideIfFork']);
            $tests = [$expr, $body];
            $else = null;
     
            $end = false;
            while (!$end) {
                switch ($stream->next()->getValue()) {

    13. in /home/devkorisnik/vendor/nystudio107/craft-templatecomments/src/web/twig/TemplateCommentsParser.php at line 243 – [Twig\TokenParser\IfTokenParser::parse](http://twig.sensiolabs.org/api/2.x/Twig/TokenParser/IfTokenParser.html#method_parse)(Twig\Token)
    237238239240241242243244245246247248249

                            throw $e;
                        }
     
                        $this->stream->next();
     
                        $subparser->setParser($this);
                        $node = $subparser->parse($token);
                        if (!$node) {
                            trigger_deprecation('twig/twig', '3.12', 'Returning "null" from "%s" is deprecated and forbidden by "TokenParserInterface".', $subparser::class);
                        } else {
                            $node->setNodeTag($subparser->getTag());
                            $rv[] = $node;
                        }

    14. in /home/devkorisnik/vendor/nystudio107/craft-templatecomments/src/web/twig/tokenparsers/CommentsTokenParser.php at line 46 – nystudio107\templatecomments\web\twig\TemplateCommentsParser::subparse([nystudio107\templatecomments\web\twig\tokenparsers\CommentsTokenParser, 'decideCommentsEnd'], true)
    40414243444546474849505152

            $lineno = $token->getLine();
            $stream = $this->parser->getStream();
            $nodes = [
                'templateName' => $this->parser->getExpressionParser()->parseExpression(),
            ];
            $stream->expect(Token::BLOCK_END_TYPE);
            $nodes['body'] = $this->parser->subparse([$this, 'decideCommentsEnd'], true);
            $stream->expect(Token::BLOCK_END_TYPE);
     
            return new CommentsNode($nodes, [], $lineno, $this->getTag());
        }
     
     

    15. in /home/devkorisnik/vendor/nystudio107/craft-templatecomments/src/web/twig/TemplateCommentsParser.php at line 243 – nystudio107\templatecomments\web\twig\tokenparsers\CommentsTokenParser::parse(Twig\Token)
    237238239240241242243244245246247248249

                            throw $e;
                        }
     
                        $this->stream->next();
     
                        $subparser->setParser($this);
                        $node = $subparser->parse($token);
                        if (!$node) {
                            trigger_deprecation('twig/twig', '3.12', 'Returning "null" from "%s" is deprecated and forbidden by "TokenParserInterface".', $subparser::class);
                        } else {
                            $node->setNodeTag($subparser->getTag());
                            $rv[] = $node;
                        }

    16. in /home/devkorisnik/vendor/nystudio107/craft-templatecomments/src/web/twig/TemplateCommentsParser.php at line 152 – nystudio107\templatecomments\web\twig\TemplateCommentsParser::subparse(null, false)
    146147148149150151152153154155156157158

            $this->traits = [];
            $this->blockStack = [];
            $this->importedSymbols = [[]];
            $this->embeddedTemplates = [];
     
            try {
                $body = $this->subparse($test, $dropNeedle);
     
                if (null !== $this->parent && null === $body = $this->filterBodyNodes($body)) {
                    $body = new Node();
                }
            } catch (SyntaxError $e) {
                if (!$e->getSourceContext()) {

    17. in /home/devkorisnik/vendor/twig/twig/src/Environment.php at line 539 – nystudio107\templatecomments\web\twig\TemplateCommentsParser::parse(Twig\TokenStream)
    533534535536537538539540541542543544545

        public function parse(TokenStream $stream): ModuleNode
        {
            if (null === $this->parser) {
                $this->parser = new Parser($this);
            }
     
            return $this->parser->parse($stream);
        }
     
        public function setCompiler(Compiler $compiler)
        {
            $this->compiler = $compiler;
        }

    18. in /home/devkorisnik/vendor/twig/twig/src/Environment.php at line 567 – [Twig\Environment::parse](http://twig.sensiolabs.org/api/2.x/Twig/Environment.html#method_parse)(Twig\TokenStream)
    561562563564565566567568569570571572573

         *
         * @throws SyntaxError When there was an error during tokenizing, parsing or compiling
         */
        public function compileSource(Source $source): string
        {
            try {
                return $this->compile($this->parse($this->tokenize($source)));
            } catch (Error $e) {
                $e->setSourceContext($source);
                throw $e;
            } catch (\Exception $e) {
                throw new SyntaxError(\sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
            }

    19. in /home/devkorisnik/vendor/craftcms/cms/src/web/twig/Environment.php at line 39 – [Twig\Environment::compileSource](http://twig.sensiolabs.org/api/2.x/Twig/Environment.html#method_compileSource)(Twig\Source)
    33343536373839404142434445

        /**
         * @inheritdoc
         */
        public function compileSource(Source $source): string
        {
            Craft::beginProfile($source->getName(), __METHOD__);
            $result = parent::compileSource($source);
            Craft::endProfile($source->getName(), __METHOD__);
            return $result;
        }
     
        /**
         * @param mixed $strategy The escaper strategy to set. If null, it will be determined based on the template name.

    20. in /home/devkorisnik/vendor/twig/twig/src/Environment.php at line 395 – craft\web\twig\Environment::compileSource(Twig\Source)
    389390391392393394395396397398399400401

                if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
                    $this->cache->load($key);
                }
     
                if (!class_exists($cls, false)) {
                    $source = $this->getLoader()->getSourceContext($name);
                    $content = $this->compileSource($source);
                    if (!isset($this->hotCache[$name])) {
                        $this->cache->write($key, $content);
                        $this->cache->load($key);
                    }
     
                    if (!class_exists($mainCls, false)) {

    21. in /home/devkorisnik/vendor/twig/twig/src/Environment.php at line 357 – [Twig\Environment::loadTemplate](http://twig.sensiolabs.org/api/2.x/Twig/Environment.html#method_loadTemplate)('__TwigTemplate_2b506d6aff2d8ef56...', 'author-toolbar/requests/_search....')
    351352353354355356357358359360361362363

            if ($name instanceof Template) {
                trigger_deprecation('twig/twig', '3.9', 'Passing a "%s" instance to "%s" is deprecated.', self::class, __METHOD__);
     
                return $name;
            }
     
            return new TemplateWrapper($this, $this->loadTemplate($this->getTemplateClass($name), $name));
        }
     
        /**
         * Loads a template internal representation.
         *
         * This method is for internal use only and should never be called

    22. in /home/devkorisnik/vendor/twig/twig/src/Environment.php at line 320 – [Twig\Environment::load](http://twig.sensiolabs.org/api/2.x/Twig/Environment.html#method_load)('author-toolbar/requests/_search....')
    314315316317318319320321322323324325326

         * @throws LoaderError  When the template cannot be found
         * @throws SyntaxError  When an error occurred during compilation
         * @throws RuntimeError When an error occurred during rendering
         */
        public function render($name, array $context = []): string
        {
            return $this->load($name)->render($context);
        }
     
        /**
         * Displays a template.
         *
         * @param string|TemplateWrapper $name The template name

    23. in /home/devkorisnik/vendor/craftcms/cms/src/web/View.php at line 570 – [Twig\Environment::render](http://twig.sensiolabs.org/api/2.x/Twig/Environment.html#method_render)('author-toolbar/requests/_search....', [])
    564565566567568569570571572573574575576

     
            // Render and return
            $renderingTemplate = $this->_renderingTemplate;
            $this->_renderingTemplate = $template;
     
            try {
                $output = $this->getTwig()->render($template, $variables);
            } finally {
                $this->_renderingTemplate = $renderingTemplate;
                $this->setTemplateMode($oldTemplateMode);
            }
     
            $this->afterRenderTemplate($template, $variables, $templateMode, $output);

    24. in /home/devkorisnik/vendor/craftcms/cms/src/web/View.php at line 623 – craft\web\View::renderTemplate('author-toolbar/requests/_search....', [])
    617618619620621622623624625626627628629

     
            $isRenderingPageTemplate = $this->_isRenderingPageTemplate;
            $this->_isRenderingPageTemplate = true;
     
            try {
                $this->beginPage();
                echo $this->renderTemplate($template, $variables);
                $this->endPage();
            } finally {
                $this->_isRenderingPageTemplate = $isRenderingPageTemplate;
                $this->setTemplateMode($oldTemplateMode);
                $output = ob_get_clean();
            }

    25. in /home/devkorisnik/vendor/craftcms/cms/src/web/TemplateResponseFormatter.php at line 57 – craft\web\View::renderPageTemplate('author-toolbar/requests/_search....', [], 'site')
    51525354555657585960616263

            ) {
                $view->registerAssetBundle(ContentWindowAsset::class);
            }
     
            // Render and return the template
            try {
                $response->content = $view->renderPageTemplate($behavior->template, $behavior->variables, $behavior->templateMode);
            } catch (Throwable $e) {
                $previous = $e->getPrevious();
                if ($previous instanceof YiiExitException) {
                    // Something called Craft::$app->end()
                    if ($previous instanceof ExitException && $previous->output !== null) {
                        echo $previous->output;

    26. in /home/devkorisnik/vendor/yiisoft/yii2/web/Response.php at line 1109 – craft\web\TemplateResponseFormatter::format(craft\web\Response)
    1103110411051106110711081109111011111112111311141115

            if (isset($this->formatters[$this->format])) {
                $formatter = $this->formatters[$this->format];
                if (!is_object($formatter)) {
                    $this->formatters[$this->format] = $formatter = Yii::createObject($formatter);
                }
                if ($formatter instanceof ResponseFormatterInterface) {
                    $formatter->format($this);
                } else {
                    throw new InvalidConfigException("The '{$this->format}' response formatter is invalid. It must implement the ResponseFormatterInterface.");
                }
            } elseif ($this->format === self::FORMAT_RAW) {
                if ($this->data !== null) {
                    $this->content = $this->data;

    27. in /home/devkorisnik/vendor/craftcms/cms/src/web/Response.php at line 341 – [yii\web\Response::prepare](https://www.yiiframework.com/doc-2.0/yii-web-response.html#prepare()-detail)()
    335336337338339340341342343344345346347

     
        /**
         * @inheritdoc
         */
        protected function prepare(): void
        {
            parent::prepare();
            $this->_isPrepared = true;
        }
     
        /**
         * Clear the output buffer to prevent corrupt downloads.
         *

    28. in /home/devkorisnik/vendor/yiisoft/yii2/web/Response.php at line 340 – craft\web\Response::prepare()
    334335336337338339340341342343344345346

        public function send()
        {
            if ($this->isSent) {
                return;
            }
            $this->trigger(self::EVENT_BEFORE_SEND);
            $this->prepare();
            $this->trigger(self::EVENT_AFTER_PREPARE);
            $this->sendHeaders();
            $this->sendContent();
            $this->trigger(self::EVENT_AFTER_SEND);
            $this->isSent = true;
        }

    29. in /home/devkorisnik/vendor/yiisoft/yii2/base/Application.php at line 390 – [yii\web\Response::send](https://www.yiiframework.com/doc-2.0/yii-web-response.html#send()-detail)()
    384385386387388389390391392393394395396

                $response = $this->handleRequest($this->getRequest());
     
                $this->state = self::STATE_AFTER_REQUEST;
                $this->trigger(self::EVENT_AFTER_REQUEST);
     
                $this->state = self::STATE_SENDING_RESPONSE;
                $response->send();
     
                $this->state = self::STATE_END;
     
                return $response->exitStatus;
            } catch (ExitException $e) {
                $this->end($e->statusCode, isset($response) ? $response : null);

    30. in /home/devkorisnik/public_html/index.php at line 24 – [yii\base\Application::run](https://www.yiiframework.com/doc-2.0/yii-base-application.html#run()-detail)()
    18192021222324

        Dotenv\Dotenv::create(CRAFT_BASE_PATH, null, $factory)->load();
    }
     
    // Load and run Craft
    define('CRAFT_ENVIRONMENT', getenv('ENVIRONMENT') ?: 'production');
    $app = require CRAFT_VENDOR_PATH.'/craftcms/cms/bootstrap/web.php';
    $app->run();

$_GET = [
    'p' => 'actions/author-toolbar/search/get-search-results-html',
];

$_COOKIE = [
    'ViewHistory' => 'c44d12be9a84ab1c284dd597b3e8907958d7897a4f6a85c4409a2a37d4e81fd6a:2:{i:0;s:11:"ViewHistory";i:1;s:125:"{"143":23,"250":6,"138064":9,"2902":2,"156":7,"136":7,"253":6,"174":7,"246":2,"198975":6,"240":4,"243":2,"237730":1,"7142":2}";}',
    '_ga_R3YRLWVQ0K' => 'GS2.1.s1762804085$o4$g1$t1762804136$j9$l0$h0',
    '_ga' => 'GA1.1.2112359368.1761829931',
    '_gcl_au' => '1.1.744987552.1761829932',
    'crisp-client%2Fsession%2Ffb01c546-1add-47d9-aca3-93b9b19dbd68' => 'session_3ba9cd94-1dfc-4298-9bfa-ea1f45b85aeb',
    '6d36deeeac1e09a51631a0533eb7975a_username' => '444244c264e8c65c53fd4487d07eca0db8c69c1d40d0f711ef4e57d3b22f4e1da:2:{i:0;s:41:"6d36deeeac1e09a51631a0533eb7975a_username";i:1;s:3:"wmd";}',
    'cc_cookie' => '{"categories":["necessary","analytics","ads"],"revision":0,"data":null,"consentTimestamp":"2025-10-30T17:27:19.099Z","consentId":"67a59615-9c84-46ef-8ff0-154ad0f918b7","services":{"necessary":[],"analytics":[],"ads":[]},"languageCode":"en","lastConsentTimestamp":"2025-10-30T17:27:19.099Z","expirationTime":1777570039100}',
    '__stripe_mid' => '898245e3-afef-446b-9ccc-bd03df4c1c531cdc3f',
    'PHPSESSID' => 'f76beae3f915172d7c0aa8dddd9ab766',
    '87c952207358c296ceba760b672c2acc_commerce_cart' => 'a6dd45535cb8e55c4852c7cb41b6c56d257485fe9df5cf9940fd556ff1976cc8a:2:{i:0;s:46:"87c952207358c296ceba760b672c2acc_commerce_cart";i:1;s:32:"c4eb619e198b8f5757c0e9dcbdc6be1e";}',
    'CRAFT_CSRF_TOKEN' => '4e5c7c7d1b03f9a68ec02b224791cf9770493504d4856611a36d5039a67681c6a:2:{i:0;s:16:"CRAFT_CSRF_TOKEN";i:1;s:147:"DCKdysVt1ChbwR_q2UMZZUOZIkPJouiNOjdoOj_C|90e367330ed158015b2a5a48efa37e3316bd676da4000b513cef6b00adb2d668DCKdysVt1ChbwR_q2UMZZUOZIkPJouiNOjdoOj_C|1";}',
    '6d36deeeac1e09a51631a0533eb7975a_identity' => 'bb7658e0d62ae592971acaacdf138c5b190b1f557c344c1d7c0ea60a8a74043ca:2:{i:0;s:41:"6d36deeeac1e09a51631a0533eb7975a_identity";i:1;s:159:"[1,"[\\"n4IAt2lue_IqmCPZgIpk63FToNETkulWczMZW61Yl9LvZzgPioGOwlWuYZmpDReuxMpHPOp-W8mUk0QVSE_edWx2uzP0-N2jhE5h\\",null,\\"bfe921b394bf10c8d08c5999edfccc8d\\"]",3600]";}',
    'Craft-0c2109e5-12e8-4073-8e34-356e7deb50e1:sidebar' => 'expanded',
];

$_SESSION = [
    'rv-recent-ids' => [
        1954 => 240,
        2231 => 174,
        2250 => 246,
        2268 => 243,
        2770 => 237730,
        3002 => 7142,
        3068 => 253,
        4142 => 250,
        4169 => 138064,
        4220 => 156,
        4237 => 143,
    ],
    'wishlist_list' => '26cacd9a792b83e769ff2a8b606a58a6',
    '6d36deeeac1e09a51631a0533eb7975a__token' => 'n4IAt2lue_IqmCPZgIpk63FToNETkulWczMZW61Yl9LvZzgPioGOwlWuYZmpDReuxMpHPOp-W8mUk0QVSE_edWx2uzP0-N2jhE5h',
    '6d36deeeac1e09a51631a0533eb7975a__id' => 1,
    '__authKey' => '["n4IAt2lue_IqmCPZgIpk63FToNETkulWczMZW61Yl9LvZzgPioGOwlWuYZmpDReuxMpHPOp-W8mUk0QVSE_edWx2uzP0-N2jhE5h",null,"bfe921b394bf10c8d08c5999edfccc8d"]',
    '6d36deeeac1e09a51631a0533eb7975a__expire' => 1763055307,
    '__duration' => 3600,
    '__elevated_timeout' => 1763048957,
    '' => [
        'editStructure:13',
    ],
    '__flash' => [],
];

Yii Framework

Expected behavior

Author Toolbar search templates should render normally with Template Comments enabled (as they do when Template Comments is disabled).

No fatal error from Twig\Parser::$env.

Additional notes / suspicion

From the error and stack trace, it looks like:

Twig 3.15’s Parser now has a typed property private Environment $env; that is set via its constructor.

TemplateCommentsParser extends Twig\Parser and is used as the parser.

When GuardTokenParser executes, $this->parser->getEnvironment() is called, but $env has not been initialized yet, causing Typed property Twig\Parser::$env must not be accessed before initialization.

My guess is that TemplateCommentsParser’s constructor may not be calling parent::__construct($env) anymore (or the parser is being instantiated in a way that bypasses the parent constructor), which is why $env is uninitialized.

If you need any extra info (project config, minimal reproduction repo, etc.), I’m happy to provide it.

wmdhosting avatar Nov 13 '25 16:11 wmdhosting

hmmmm. It's interesting to me that this problem only appears to happen specifically with the Author Toolbar plugin installed, yes? In other words, everything works fine if that plugin is not installed?

I wonder if there is anything they are doing that could be specific to causing this issue to surface?

khalwat avatar Nov 19 '25 02:11 khalwat

i frist contacted them.. but seems they dont use anything to cause that .: https://github.com/tim-digitalastronaut/craft-author-toolbar/issues/8

AI says this.. :)

This is indeed a compatibility regression between Template Comments 5.0.4 and Twig 3.15.

In Twig 3.15, the Twig\Parser class updated the $env property to be a typed private Environment $env property, which must be initialized via the constructor.

The TemplateCommentsParser class extends Twig\Parser and overrides the __construct method, but it currently does not call parent::__construct($env). In previous versions of Twig/PHP, this might have failed silently or worked due to looser typing, but PHP 8.3 + Twig 3.15 enforces strict initialization.

Here is how to fix this immediately on your installation and how to report it.

  1. The Immediate Fix (Patching the Vendor File) To get your Author Toolbar working again without disabling Template Comments, you need to manually patch one file.

File to edit: vendor/nystudio107/craft-templatecomments/src/web/twig/TemplateCommentsParser.php

The Change: Find the __construct method (usually around line 46) and add the call to the parent constructor.

Diff

    public function __construct(Environment $env)
    {
+       parent::__construct($env);
        $this->returnComments = TemplateComments::$settings->siteSettings->returnComments;
    }
Contextual code block:

PHP

    // inside TemplateCommentsParser.php

    public function __construct(Environment $env)
    {
        // Add this line immediately:
        parent::__construct($env); 
        
        $this->returnComments = TemplateComments::$settings->siteSettings->returnComments;
    }

Save the file, and the error should disappear immediately.

  1. The Permanent Fix Since this is a bug in the plugin code, it needs to be fixed by the maintainer (nystudio107).

I have checked the issue tracker for nystudio107/craft-templatecomments, and it appears this specific Twig 3.15 incompatibility might not be reported yet, or is very recent.

wmdhosting avatar Nov 19 '25 05:11 wmdhosting

If you uninstall craft-author-toolbar does this still happen?

I ask because on the latest verison of Craft & Template Comments, I do not encounter this error.

Can you do a composer update -W to ensure you're using the latest of everything?

khalwat avatar Dec 17 '25 23:12 khalwat

BTW I should note that I'm using PHP 8.2, versus the PHP 8.3 that you're using.

khalwat avatar Dec 17 '25 23:12 khalwat

Its on 8.3 . only.. its ok .. will disable Template comments..

wmdhosting avatar Dec 18 '25 05:12 wmdhosting

@wmdhosting I'd really like to fix it. Can you see what happens if you disable craft-author-toolbar temporarily?

khalwat avatar Dec 18 '25 15:12 khalwat

Error is inside.. Toolbar search widget..

wmdhosting avatar Dec 18 '25 16:12 wmdhosting

Looks like Craft updated to Twig ~3.15 in Craft 5.6.x -> https://github.com/craftcms/cms/blob/5.x/CHANGELOG.md#560---2025-01-21

So I will update Template Comments to Twig 3.15 and bump the minimum requirements for craftcms/cms/ ^5.6.0,

khalwat avatar Dec 18 '25 16:12 khalwat

Addressed in the above commits.

You can try it now by setting your semver in your composer.json to look like this:

    "nystudio107/craft-templatecomments": "dev-develop-v5 as 5.0.5”,

Then do a composer clear-cache && composer update

@wmdhosting give it a whirl and lmk

khalwat avatar Dec 18 '25 22:12 khalwat

@wmdhosting ?

khalwat avatar Jan 27 '26 00:01 khalwat

Sorry was quite busy latetly. all ok now. thx :)

wmdhosting avatar Jan 27 '26 09:01 wmdhosting

Released as 5.0.5

khalwat avatar Jan 29 '26 21:01 khalwat