twigphp/Twig · error · RuntimeError

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

Error message

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

What it means

The Twig 'column' filter (CoreExtension::column) extracts a column from an array of arrays/objects. It throws this RuntimeError when the input is not iterable (not array and not Traversable), e.g. null, a scalar, or a single entity.

Solutions

  1. Coerce the input to an array before the filter (e.g. (value ?? [])|column('name'))
  2. Fix the upstream data provider to always return an array/Collection
  3. Use the 'iterable' test to branch in the template: {% if items is iterable %}...{% endif %}

Example fix

// before
{{ users|column('email') }}

// after
{{ (users ?? [])|column('email') }}
Defensive patterns

Strategy: validation

Validate before calling

if (!is_iterable($users)) { $users = []; }
// or in template: {% if users is iterable %}{{ users|column('email') }}{% endif %}

Type guard

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

Try / catch

try { $out = $twig->render($tpl, $ctx); } catch (\Twig\Error\RuntimeError $e) { if (str_contains($e->getMessage(), '"column" filter')) { /* normalize input to array */ } }

Prevention

When it happens

Trigger: Using {{ value|column('name') }} where value is null, false, an int/string, or an object that is not Traversable — typically when the data source returned no list or a single record.

Common situations: Doctrine repository returning null on find() instead of an array; a query returning one row instead of a collection; unserialized/missing request data passed to the filter; API responses yielding null on error.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13). Data as JSON: /api/errors/7854d096e69729ac. Report an issue: GitHub.

Appendix: source

Thrown at src/Extension/CoreExtension.php:2025

     *  {% set items = [{ 'fruit' : 'apple'}, {'fruit' : 'orange' }] %}
     *
     *  {% set fruits = items|column('fruit') %}
     *
     *  {# fruits now contains ['apple', 'orange'] #}
     * </pre>
     *
     * @param array|\Traversable $array An array
     * @param int|string         $name  The column name
     * @param int|string|null    $index The column to use as the index/keys for the returned array
     *
     * @return array The array of values
     *
     * @internal
     */
    public static function column(Environment $env, bool $isSandboxed, $array, $name, $index = null): array
    {
        if (!is_iterable($array)) {
            throw new RuntimeError(\sprintf('The "column" filter expects a sequence or a mapping, got "%s".', get_debug_type($array)));
        }

        if ($array instanceof \Traversable) {
            $array = iterator_to_array($array);
        }

        if ($isSandboxed) {
            // The sandbox might be enabled via a SourcePolicyInterface, in which case the SandboxExtension
            // would not consider the sandbox active without the current Source: $isSandboxed is already
            // computed against the call-site source, so check the policy directly to honor that decision.
            $policy = $env->getExtension(SandboxExtension::class)->getChecker()->getSecurityPolicy();
            foreach ($array as $item) {
                if (\is_object($item)) {
                    $policy->checkPropertyAllowed($item, (string) $name);
                    if (null !== $index) {
                        $policy->checkPropertyAllowed($item, (string) $index);
                    }
                }

View on GitHub (pinned to a414c3a491)