twigphp/Twig · error · RuntimeError
The "replace" filter expects a sequence or a mapping, got
Error message
The "replace" filter expects a sequence or a mapping, got "%s".
What it means
The Twig `replace` filter calls CoreExtension::replace, which requires the second argument (`from`) to be iterable — a sequence (array) or a mapping of search=>replace pairs, passed to strtr(). If the argument is a scalar, null, or object that is not Traversable/Array, a Twig\Error::RuntimeError is thrown naming the actual PHP debug type.
Solutions
- Make the second argument an array or mapping, e.g. {{ 'a-b'|replace({'-': '_'}) }}.
- Dump the variable ({{ dump(x) }}) and check its debug type in the message to find where it became non-iterable.
- If the value may be null, default it first: {{ 'abc'|replace(x|default({})) }}.
- Cast Traversable to array with iterator_to_array or the |column/filter family when appropriate before replacing.
Example fix
// before (template)
{{ 'hello world'|replace(' ') }}
// after
{{ 'hello world'|replace({' ': '_'}) }} Defensive patterns
Strategy: validation
Validate before calling
// Twig template
{% if x is iterable %}{{ str|replace(x) }}{% else %}{{ str }}{% endif %}
// PHP before calling the filter
echo \is_iterable($from) ? \Twig\Extension\CoreExtension::replace($str, $from) : $str; Type guard
function isReplaceSource($v): bool { return \is_iterable($v); } Try / catch
try {
$out = \Twig\Extension\CoreExtension::replace($str, $from);
} catch (\Twig\Error\RuntimeError $e) {
$out = $str; // or log and rethrow
} Prevention
- Always pass mapping literals like {'search': 'replace'} to replace.
- Use |default({}) for possibly-null variables.
- Verify variable types with the dump() function during development.
- Remember json_decode must use assoc=true (or objects must be Traversable) before use in Twig filters.
When it happens
Trigger: Calling {{ 'abc'|replace(x) }} where x is a string, integer, boolean, null, or a non-Traversable object instead of an array or Traversable; also when a variable that was expected to be an array is actually null (e.g. missing context var or a function returning null).
Common situations: Passing a plain string like {{ 'a-b'|replace('-': '_') }}-style mistakes with wrong filter syntax; passing null because an upstream variable was unset; passing an stdClass result from json_decode without assoc=true; assuming another filter (e.g. split) returned an array but it returned null on failure.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- The "merge" 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.
- Attributes using InlineStyle can only be merged with…
- Only iterable values can be appended to InlineStyle.
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/b46735ce02aeaf19.
Report an issue: GitHub.
Appendix: source
Thrown at src/Extension/CoreExtension.php:652
if (false !== $timezone) {
$date->setTimezone($timezone);
}
return $date;
}
/**
* Replaces strings within a string.
*
* @param string|null $str String to replace in
* @param array|\Traversable $from Replace values
*
* @internal
*/
public static function replace($str, $from): string
{
if (!is_iterable($from)) {
throw new RuntimeError(\sprintf('The "replace" filter expects a sequence or a mapping, got "%s".', get_debug_type($from)));
}
return strtr($str ?? '', self::toArray($from));
}
/**
* Rounds a number.
*
* @param int|float|string|null $value The value to round
* @param int|float $precision The rounding precision
* @param 'common'|'ceil'|'floor' $method The method to use for rounding
*
* @return float The rounded number
*
* @internal
*/
public static function round($value, $precision = 0, $method = 'common')
{View on GitHub (pinned to a414c3a491)