twigphp/Twig · error · RuntimeError
The "find" filter expects a sequence or a mapping, got
Error message
The "find" filter expects a sequence or a mapping, got "%s".
What it means
The Twig `find` filter (CoreExtension::find) requires its first argument to be iterable — an array, Traversable, or object implementing iterable. Twig throws this RuntimeError when the value piped into `find` is a scalar (string, int, bool, null, etc.) instead of a sequence or mapping. It is thrown at runtime in PHP, not at template compile time, because the argument type cannot always be statically known.
Solutions
- Guard the value in the template before filtering: use the `default` filter or an `is iterable` test, e.g. `{{ (items ?? [])|find(...) }}`.
- Fix the data source so the variable actually contains an array/Traversable (check the controller/context assignment).
- If the value may legitimately be a scalar, branch with `{% if items is iterable %}...{% else %}...{% endif %}`.
- Catch Twig\Error\RuntimeError around the render call to surface the offending variable name via the template trace.
Example fix
// before (Twig)
{{ user.roles|find(role => role == 'ADMIN') }}
// after
{% if user.roles is iterable %}
{{ user.roles|find(role => role == 'ADMIN') }}
{% endif %} Defensive patterns
Strategy: validation
Validate before calling
// PHP, before rendering
def ensure_iterable_for_find($value): void {
if (!is_iterable($value)) {
throw new InvalidArgumentException('find() 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(), '"find" filter expects a sequence or a mapping')) {
// log offending variable, render fallback
} else { throw $e; }
} Prevention
- Always default nullable collections with `?? []` in Twig before piping into filters
- In PHP controllers, normalize context arrays with `$value ?? []`
- Make repository/service methods return `[]` instead of null/false on empty results
- Use `{% if x is iterable %}` guards around filter chains on data of uncertain shape
When it happens
Trigger: Calling `{{ [1,2,3]|find(v => v > 1) }}` where the value before the filter is actually a scalar — e.g. `{{ some_var|find(v => v) }}` where some_var is null, a string, or an int. The guard is `if (!is_iterable($array))` at CoreExtension.php:2079.
Common situations: A variable that is usually an array is null on this code path (e.g. a missing relation or unset context key); a function returns false/null on failure instead of an array; a doctrine collection was not initialized; passing a scalar from config into a filter chain.
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
- The "map" filter expects a sequence or a mapping, got
- The "reduce" filter expects a sequence or a mapping, got
- The "batch" filter expects a sequence or a mapping, got
- The "has some" test expects a sequence or a mapping, got
- The "has every" test expects a sequence or a mapping, got
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/f771752fbf257149.
Report an issue: GitHub.
Appendix: source
Thrown at src/Extension/CoreExtension.php:2079
self::checkArrow($isSandboxed, $arrow, 'filter', 'filter');
if (\is_array($array)) {
return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH);
}
// the IteratorIterator wrapping is needed as some internal PHP classes are \Traversable but do not implement \Iterator
return new \CallbackFilterIterator(new \IteratorIterator($array), $arrow);
}
/**
* @param \Closure $arrow
*
* @internal
*/
public static function find(Environment $env, bool $isSandboxed, $array, $arrow)
{
if (!is_iterable($array)) {
throw new RuntimeError(\sprintf('The "find" filter expects a sequence or a mapping, got "%s".', get_debug_type($array)));
}
self::checkArrow($isSandboxed, $arrow, 'find', 'filter');
foreach ($array as $k => $v) {
if ($arrow($v, $k)) {
return $v;
}
}
return null;
}
/**
* @param \Closure $arrow
*
* @internal
*/View on GitHub (pinned to a414c3a491)