twigphp/Twig · error · SyntaxError
A default value for an argument must be a constant (a…
Error message
A default value for an argument must be a constant (a boolean, a string, a number, a sequence, or a mapping).
What it means
Macro argument defaults must be constant expressions (literal booleans, strings, numbers, arrays/sequences, or mappings). Twig evaluates defaults at compile time, so dynamic expressions like variables, function calls, or operators as default values are rejected.
Solutions
- Replace the dynamic default with a literal constant (e.g. null or '') and compute the real value inside the macro body
- Use a conditional inside the macro: '{% if a is none %}{% set a = some_var %}{% endif %}'
- Pass the dynamic value explicitly at every call site instead of defaulting it
Example fix
// before
{% macro greet(name = app.user.name) %}
// after
{% macro greet(name = null) %}{% set name = name ?? app.user.name %} Defensive patterns
Strategy: validation
Validate before calling
// Keep a whitelist check for default expressions in macro docs/templates
if (preg_match('/=\s*(?!true|false|null|none|\d|([\'\"])[^\'\"]*\1|\[|\{)\S/', $macroSignature)) {
// flag suspicious non-constant default for review
} Try / catch
try {
$twig->render($template, $context);
} catch (SyntaxError $e) {
if (str_contains($e->getMessage(), 'must be a constant')) {
// fall back to a version of the macro with literal defaults
}
throw $e;
} Prevention
- Use only literals (bool, string, number, [] , {}) as macro argument defaults
- Compute dynamic values inside the macro body with {% set %} / the ?? operator
- Pass dynamic values explicitly at call sites
When it happens
Trigger: Writing '{% macro m(a = some_var) %}' or '{% macro m(a = date()) %}' or '{% macro m(a = 1 + 2) %}'; checkConstantExpression fails and parseDefinition throws.
Common situations: Trying to default an argument to another macro argument, an environment variable, or the result of a function/filter — patterns developers carry over from PHP function signatures.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Expected endmacro for macro
- The variadic argument
- The variadic argument
- An exception has been thrown during the compilation of a…
- Calling the "parent" function outside of a block is…
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/781194d3a46f4d69.
Report an issue: GitHub.
Appendix: source
Thrown at src/TokenParser/MacroTokenParser.php:121
if ($stream->nextIf(Token::PUNCTUATION_TYPE, ',') && !$stream->test(Token::PUNCTUATION_TYPE, ')')) {
throw new SyntaxError(\sprintf('The variadic argument "%s" in macro "%s" must be the last one.', $variadicName, $macroName), $token->getLine(), $stream->getSourceContext());
}
break;
}
$token = $stream->expect(Token::NAME_TYPE, null, 'An argument must be a name');
$name = new LocalVariable($token->getValue(), $token->getLine());
NodeDocumentation::add($name, $token);
if ($token = $stream->nextIf(Token::OPERATOR_TYPE, '=')) {
$default = $this->parser->parseExpression();
} else {
$default = new ConstantExpression(null, $this->parser->getCurrentToken()->getLine());
$default->setAttribute('is_implicit', true);
}
if (!$this->checkConstantExpression($default)) {
throw new SyntaxError('A default value for an argument must be a constant (a boolean, a string, a number, a sequence, or a mapping).', $token->getLine(), $stream->getSourceContext());
}
$arguments->addElement($default, $name);
}
$stream->expect(Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
return [$arguments, $variadicName];
}
// checks that the node only contains "constant" elements
private function checkConstantExpression(Node $node): bool
{
if (!($node instanceof ConstantExpression || $node instanceof ArrayExpression
|| $node instanceof NegUnary || $node instanceof PosUnary
)) {
return false;
}
foreach ($node as $n) {View on GitHub (pinned to a414c3a491)