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

  1. Ensure both operands are arrays: {{ a|merge(b) }} with a and b as arrays or Traversables.
  2. Check the argument number in the message, dump that variable, and fix its origin.
  3. Guard with defaults: {{ (a|default([]))|merge(b|default([])) }}.
  4. 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

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


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)