twigphp/Twig · error · RuntimeError
The "merge" filter expects a sequence or a mapping, got
Error message
The "merge" filter expects a sequence or a mapping, got "%s" for argument %d.
What it means
The Twig `merge` filter (CoreExtension::merge) accepts one or more arguments and requires every argument to be iterable (array or Traversable); each is converted via toArray and merged with array_merge. If argument N is not iterable, a RuntimeError is thrown reporting the debug type and 1-based argument number.
Solutions
- Ensure both operands are arrays: {{ a|merge(b) }} with a and b as arrays or Traversables.
- Check the argument number in the message, dump that variable, and fix its origin.
- Guard with defaults: {{ (a|default([]))|merge(b|default([])) }}.
- Cast a non-Traversable object to array first or use |to_array-like conversions; for scalars, wrap as [value] if merging into a list is intended.
Example fix
// before (template)
{% set all = items|merge(null) %}
// after
{% set all = items|merge(extra|default([])) %} Defensive patterns
Strategy: type-guard
Validate before calling
// Twig template
{% if a is iterable and b is iterable %}{% set all = a|merge(b) %}{% endif %} Type guard
function canMerge(...$args): bool { foreach ($args as $a) { if (!\is_iterable($a)) { return false; } } return true; } Try / catch
try {
$out = \Twig\Extension\CoreExtension::merge($a, $b);
} catch (\Twig\Error\RuntimeError $e) {
$out = \array_merge(\is_iterable($a) ? \iterator_to_array($a) : [], \is_iterable($b) ? \iterator_to_array($b) : []);
} Prevention
- Default nullable operands: {{ (a|default([]))|merge(b|default([])) }}.
- Ensure JSON decoding produces arrays (json_decode($json, true)).
- Check the argument number in the error message to locate the offending operand quickly.
When it happens
Trigger: {{ a|merge(b) }} where a or b is null, a scalar, boolean, or a non-Traversable object; merge with several arguments where any one is non-iterable (the message reports which argument number).
Common situations: Merging a null variable produced by an optional query result; merging an stdClass from json_decode without array output; merging a string assuming it will be treated as a list; refactors where a variable changed from array to collection-less scalar.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Attributes using InlineStyle can only be merged with…
- The "replace" filter expects a sequence or a mapping, got
- The "sort" filter expects a sequence or a mapping, got
- InlineStyle can only be created from iterable values.
- Only iterable values can be appended to InlineStyle.
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/85ea5ce7bfedc093.
Report an issue: GitHub.
Appendix: source
Thrown at src/Extension/CoreExtension.php:749
* Merges any number of arrays or Traversable objects.
*
* {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
*
* {% set items = items|merge({ 'peugeot': 'car' }, { 'banana': 'fruit' }) %}
*
* {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car', 'banana': 'fruit' } #}
*
* @param array|\Traversable ...$arrays Any number of arrays or Traversable objects to merge
*
* @internal
*/
public static function merge(...$arrays): array
{
$result = [];
foreach ($arrays as $argNumber => $array) {
if (!is_iterable($array)) {
throw new RuntimeError(\sprintf('The "merge" filter expects a sequence or a mapping, got "%s" for argument %d.', get_debug_type($array), $argNumber + 1));
}
$result = array_merge($result, self::toArray($array));
}
return $result;
}
/**
* Slices a variable.
*
* @param mixed $item A variable
* @param int $start Start of the slice
* @param int $length Size of the slice
* @param bool $preserveKeys Whether to preserve key or not (when the input is an array)
*
* @return mixed The sliced variable
*View on GitHub (pinned to a414c3a491)