twigphp/Twig · error · Error

%s: %s

Error message

%s: %s

What it means

In Twig's integration test suite (Test/IntegrationTestCase::doIntegrationTest), when a test case expects an exception and one is thrown but does not match the expectation (or does not satisfy prior assertions like message wording), the suite rethrows it wrapped in a plain Error formatted as "ExceptionClass: message". This is test-harness plumbing: it preserves the original exception as $previous while flattening it for phpUnit failure output.

Solutions

  1. Read the wrapped original exception (given as the Error's previous) to see what actually failed.
  2. Update the fixture's EXPECTED exception line to match the actual exception class and message.
  3. If the message text changed intentionally, update the message and keep it ending with '.' or '?' to pass formatting assertions.
  4. Fix the library code if the new exception is a regression.

Example fix

--EXPECT--
LogicException: Foo bar

{# after: match actual exception #}
--EXPECT EXCEPTION--
Twig\Error\SyntaxError: Unexpected token "foo".
Defensive patterns

Strategy: try-catch

Try / catch

// In test fixtures, align expectations with reality:
// --EXPECT EXCEPTION--
// Twig\Error\SyntaxError: <message ending with '.' or '?'>.
// The harness rethrows as Error with the original as previous — read getPrevious() when debugging.

Prevention

When it happens

Trigger: A .test integration fixture declares an exception (or deprecation) expectation, but the code under test throws a different exception class or a message that fails the suite's assertions (e.g. message not ending with '.' or '?'), so Error(sprintf('%s: %s', ...)) is raised inside testIntegration/testLegacyIntegration.

Common situations: Contributing a patch to Twig and writing integration test fixtures whose expected exception message/class doesn't match the actual thrown error; changes to error messages breaking the suite's message-format assertions.

Related errors


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

Appendix: source

Thrown at src/Test/IntegrationTestCase.php:324

                    }

                    return $prevHandler ? $prevHandler($type, $msg, $file, $line, $context) : false;
                });

                foreach (array_keys($templateSources) as $templateName) {
                    $templates[$templateName] = $twig->load($templateName);
                }
            } catch (\Exception $e) {
                if (false !== $exception) {
                    $message = $e->getMessage();
                    $this->assertSame(trim($exception), trim(\sprintf('%s: %s', $e::class, $message)));
                    $last = substr($message, \strlen($message) - 1);
                    $this->assertTrue('.' === $last || '?' === $last, 'Exception message must end with a dot or a question mark.');

                    return;
                }

                throw new Error(\sprintf('%s: %s', $e::class, $e->getMessage()), -1, null, $e);
            } finally {
                restore_error_handler();
            }

            $template = $templates['index.twig'];
            $captureRenderDeprecations = '' !== $deprecation;

            try {
                if ($captureRenderDeprecations) {
                    $prevHandler = set_error_handler(static function ($type, $msg, $file, $line, $context = []) use (&$deprecations, &$prevHandler) {
                        if (\E_USER_DEPRECATED === $type) {
                            $deprecations[] = $msg;

                            return true;
                        }

                        return $prevHandler ? $prevHandler($type, $msg, $file, $line, $context) : false;
                    });

View on GitHub (pinned to a414c3a491)