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

  1. Check spelling/case against the valid list: html, js, url, css, html_attr, html_attr_relaxed.
  2. Register the intended custom escaper with $runtime->registerEscaper($name, $callable) before escaping.
  3. Default to 'html' when the strategy is dynamic: $strategy = $allowed[$input] ?? 'html'.
  4. 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

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


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)