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
- Read the wrapped original exception (given as the Error's previous) to see what actually failed.
- Update the fixture's EXPECTED exception line to match the actual exception class and message.
- If the message text changed intentionally, update the message and keep it ending with '.' or '?' to pass formatting assertions.
- 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
- Keep EXPECT EXCEPTION blocks in fixtures exactly matching class and message.
- Ensure expected exception messages end with '.' or '?' per suite rules.
- Run the integration suite locally before committing parser/compiler changes.
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
- Not implemented.
- Test " " is not valid.
- Unknown " " configuration.
- The " " modifier takes exactly one argument (0 given).
- The " " modifier takes exactly one argument (2 given).
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)