twigphp/Twig · error · RuntimeError

The "map" filter expects a sequence or a mapping, got

Error message

The "map" filter expects a sequence or a mapping, got "%s".

What it means

The Twig `map` filter (CoreExtension::map, invoked via the twig_array_map helper) requires an iterable argument to transform element-by-element. Twig throws this RuntimeError when the piped value is not an array or Traversable. Because Twig filters are applied at runtime, non-iterable input is only detected when the template executes.

Solutions

  1. Coerce to array first: `{{ (value ?? [])|map(...) }}` or wrap with `|default([])`.
  2. Verify what the producing expression returns and fix it at the source (controller, repository, service).
  3. Use `{% if value is iterable %}` to branch when the type legitimately varies.
  4. Catch Twig\Error\RuntimeError in the rendering code and log the template line to identify the variable.

Example fix

// before (Twig)
{{ prices|map(p => p * 1.2) }}

// after
{{ (prices ?? [])|map(p => p * 1.2) }}
Defensive patterns

Strategy: validation

Validate before calling

// PHP, before rendering
def ensure_iterable_for_map($value): void {
    if (!is_iterable($value)) {
        throw new InvalidArgumentException('map() input must be iterable, got ' . get_debug_type($value));
    }
}

Type guard

function isIterable($v): bool { return is_array($v) || $v instanceof \Traversable; }

Try / catch

try {
    $html = $twig->render('tpl.html.twig', $context);
} catch (\Twig\Error\RuntimeError $e) {
    if (str_contains($e->getMessage(), '"map" filter expects a sequence or a mapping')) {
        // log variable name, fall back to empty rendering
    } else { throw $e; }
}

Prevention

When it happens

Trigger: `{{ value|map(v => v * 2) }}` where value is null, a string, an int, or a bool. Also happens when a helper function returns false on error and its result is piped straight into `map`. Guard at CoreExtension.php:2101.

Common situations: Null context variables (missing optional data), API/config values that are strings rather than arrays, a function returning `false` instead of `[]` on empty results, refactors where a variable changed from collection to single entity.

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/671a672678b3068e. Report an issue: GitHub.

Appendix: source

Thrown at src/Extension/CoreExtension.php:2101

        foreach ($array as $k => $v) {
            if ($arrow($v, $k)) {
                return $v;
            }
        }

        return null;
    }

    /**
     * @param \Closure $arrow
     *
     * @internal
     */
    public static function map(Environment $env, bool $isSandboxed, $array, $arrow)
    {
        if (!is_iterable($array)) {
            throw new RuntimeError(\sprintf('The "map" filter expects a sequence or a mapping, got "%s".', get_debug_type($array)));
        }

        self::checkArrow($isSandboxed, $arrow, 'map', 'filter');

        $r = [];
        foreach ($array as $k => $v) {
            $r[$k] = $arrow($v, $k);
        }

        return $r;
    }

    /**
     * @param \Closure $arrow
     *
     * @internal
     */
    public static function reduce(Environment $env, bool $isSandboxed, $array, $arrow, $initial = null)

View on GitHub (pinned to a414c3a491)