twigphp/Twig · error · RuntimeError
Invalid escaping strategy
Error message
Invalid escaping strategy "%s" (valid ones: "%s").
What it means
EscaperRuntime::escape() throws this when the requested escaping strategy name is neither one of the built-ins (html, js, url, css, html_attr, html_attr_relaxed) nor a key registered via registerEscaper(). It fails fast rather than falling back to a default strategy.
Solutions
- Check spelling/case against the valid list: html, js, url, css, html_attr, html_attr_relaxed.
- Register the intended custom escaper with $runtime->registerEscaper($name, $callable) before escaping.
- Default to 'html' when the strategy is dynamic: $strategy = $allowed[$input] ?? 'html'.
- Validate the strategy against an allowlist before passing it to escape().
Example fix
// before
{{ value|escape(strategy) }} {# strategy = 'htm' #}
// after
{% set strategy = strategy in ['html','js','url','css','html_attr','html_attr_relaxed'] ? strategy : 'html' %}
{{ value|escape(strategy) }} Defensive patterns
Strategy: validation
Validate before calling
const VALID = ['html','js','url','css','html_attr','html_attr_relaxed'];
if (!in_array($strategy, VALID, true) && !array_key_exists($strategy, $escapers)) {
throw new \InvalidArgumentException("Unknown strategy $strategy");
} Type guard
function isTwigStrategy(string $s): bool {
return in_array($s, ['html','js','url','css','html_attr','html_attr_relaxed'], true);
} Try / catch
try {
$out = $escaper->escape($env, $value, $strategy);
} catch (\Twig\Error\RuntimeError $e) {
if (str_starts_with($e->getMessage(), 'Invalid escaping strategy')) {
$out = $escaper->escape($env, $value, 'html');
} else { throw $e; }
} Prevention
- Use an enum/const list of strategies instead of free-form strings.
- Never pass user-controlled values directly as the strategy.
- Register custom escapers during bootstrap, before any render.
- Match strategy casing exactly — lookups are case-sensitive.
When it happens
Trigger: Passing a typo'd or nonexistent strategy string: |escape('htm'), escape($env, $s, 'HTML_ATTR') (lookups are case-sensitive), a strategy variable resolved at runtime that is empty/null-derived, or referencing a custom escaper before registerEscaper() was called on the runtime.
Common situations: Strategy chosen dynamically from config or user input; upgrading Twig where a strategy was renamed; forgetting to register a custom escaper before rendering.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- The string to escape is not a valid UTF-8 string.
- An escaping strategy must be a string or false.
- Locale " " is not supported.
- A block chain requires at least one template.
- Optimizer mode " " is not valid.
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/aa916c4b46a31c7e.
Report an issue: GitHub.
Appendix: source
Thrown at src/Runtime/EscaperRuntime.php:328
}, $string);
if ('UTF-8' !== $charset) {
$string = iconv('UTF-8', $charset, $string);
}
return $string;
case 'url':
return rawurlencode($string);
default:
if (\array_key_exists($strategy, $this->escapers)) {
return $this->escapers[$strategy]($string, $charset);
}
$validStrategies = implode('", "', array_merge(['html', 'js', 'url', 'css', 'html_attr', 'html_attr_relaxed'], array_keys($this->escapers)));
throw new RuntimeError(\sprintf('Invalid escaping strategy "%s" (valid ones: "%s").', $strategy, $validStrategies));
}
}
private function convertEncoding(string $string, string $to, string $from)
{
if (!\function_exists('iconv')) {
throw new RuntimeError('Unable to convert encoding: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.');
}
return iconv($from, $to, $string);
}
}
View on GitHub (pinned to a414c3a491)