twigphp/Twig · error · Twig\Error\RuntimeError

Only empty strings may be passed as string arguments to…

Error message

Only empty strings may be passed as string arguments to html_attr_merge. This is to support the implicit else clause for ternary operators.

What it means

html_attr_merge() merges attribute arrays but forbids non-empty string arguments. Empty strings are allowed only to support Twig's implicit ternary else clause (cond ? attrs : ''); any other string would be ambiguous and is rejected.

Solutions

  1. Convert the string to an associative array first, e.g. ['class' => 'foo'].
  2. Only pass '' (empty string) or arrays/false/null to the merge.
  3. Check each merge operand is_array($x) || '' === $x || null === $x || false === $x before calling.

Example fix

// before
html_attr_merge(['class' => 'a'], 'id=main')
// after
html_attr_merge(['class' => 'a'], ['id' => 'main'])
Defensive patterns

Strategy: validation

Validate before calling

foreach ($operands as $op) { if (!is_array($op) && '' !== $op && null !== $op && false !== $op) throw new \TypeError('html_attr_merge operands must be arrays or empty strings'); }

Type guard

function isMergeOperand(mixed $v): bool { return is_array($v) || '' === $v || null === $v || false === $v; }

Try / catch

try { $attrs = html_attr_merge($base, $extra); } catch (Twig\Error\RuntimeError $e) { $attrs = $base; }

Prevention

When it happens

Trigger: Calling twig_html_attr_merge() with a non-empty string argument, e.g. merging an array with 'foo=bar' instead of ['foo' => 'bar'].

Common situations: Trying to merge a raw attribute string with an array; a ternary branch accidentally returning a string instead of an array; passing query-string-like text expecting it to be parsed.

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


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

Appendix: source

Thrown at extra/html-extra/HtmlExtension.php:160

            'sst' => new SeparatedTokenList($value, ' '),
            'cst' => new SeparatedTokenList($value, ', '),
            'style' => new InlineStyle($value),
            default => throw new RuntimeError(\sprintf('Unknown attribute type "%s" The only supported types are "sst", "cst" and "style".', $type)),
        };
    }

    /** @internal */
    public static function htmlAttrMerge(iterable|string|false|null ...$arrays): array
    {
        $result = [];

        foreach ($arrays as $array) {
            if (!$array) {
                continue;
            }

            if (\is_string($array)) {
                throw new RuntimeError('Only empty strings may be passed as string arguments to html_attr_merge. This is to support the implicit else clause for ternary operators.');
            }

            foreach ($array as $key => $value) {
                if (!isset($result[$key])) {
                    $result[$key] = $value;

                    continue;
                }

                $existing = $result[$key];

                switch (true) {
                    case $value instanceof MergeableInterface:
                        $result[$key] = $value->mergeInto($existing);
                        break;
                    case $existing instanceof MergeableInterface:
                        $result[$key] = $existing->appendFrom($value);
                        break;

View on GitHub (pinned to a414c3a491)