rectorphp/rector · error · InvalidEregException

unescaped metacharacter "%s"

Error message

unescaped metacharacter "%s"

What it means

This InvalidEregException is thrown when the ERE-to-PCRE converter meets a quantifier character '*', '+' or '?' at a position where there is no preceding atom to quantify — the start of the pattern or the start of a branch after '|', or two quantifiers in a row. In POSIX ERE such input is invalid, so EregToPcreTransformer refuses it (EregToPcreTransformer.php:125) and the ereg-to-preg conversion stops.

Source

Thrown at rules/Php70/EregToPcreTransformer.php:125

                $cls = '';
                if ($i < $l && $content[$i] === '^') {
                    $cls .= '^';
                    ++$i;
                }
                if ($i >= $l) {
                    throw new InvalidEregException('"[" does not have a matching "]"');
                }
                $start = \true;
                $i = (int) $i;
                [$cls, $i] = $this->processSquareBracket($content, $i, $l, $cls, $start);
                if ($i >= $l) {
                    throw new InvalidEregException('"[" does not have a matching "]"');
                }
                $r[$rr] .= '[' . $cls . ']';
            } elseif ($char === ')') {
                break;
            } elseif (in_array($char, ['*', '+', '?'], \true)) {
                throw new InvalidEregException('unescaped metacharacter "' . $char . '"');
            } elseif ($char === '{') {
                if ($i + 1 < $l && strpos('0123456789', $content[$i + 1]) !== \false) {
                    $r[$rr] .= '\{';
                } else {
                    throw new InvalidEregException('unescaped metacharacter "' . $char . '"');
                }
            } elseif ($char === '.') {
                $r[$rr] .= $char;
            } elseif ($char === '^' || $char === '$') {
                $r[$rr] .= $char;
                ++$i;
                continue;
            } elseif ($char === '|') {
                if ($r[$rr] === '') {
                    $normalizeUnprintableChar = \true;
                }
                $r[] = '';
                ++$rr;

View on GitHub (pinned to 408fcb0ff1)

Solutions

  1. Fix the pattern in the source file Rector reported: remove the orphan quantifier ('*abc' -> 'abc') or escape it ('\*\.txt') if it is meant literally.
  2. If the string was a glob, not a regex, switch the legacy call to fnmatch()-style logic instead of letting rector convert it to preg_match.
  3. Re-run rector; preflight-scan literal ereg/split patterns for leading or doubled quantifiers in big migrations.

Example fix

// before - quantifier with no atom (glob habit)
ereg('*.txt', $filename);

// after - escaped literal
ereg('\*\.txt', $filename); // rector: preg_match('#\*\.txt#m', $filename)
Defensive patterns

Strategy: try-catch

Validate before calling

// quick lint: quantifier at pattern start or after '|' / another quantifier
function hasOrphanQuantifier(string $p): bool {
    return (bool) preg_match('~(^|\||[+*?])[+*?]~', $p);
}

Try / catch

try {
    $pcre = $eregToPcreTransformer->transform($pattern, $ignoreCase);
} catch (InvalidEregException $e) {
    // '*'/'+'/'?' with no atom to quantify — remove or escape it, then re-run
    continue;
}

Prevention

When it happens

Trigger: Rector (Php70 set / EregToPregMatchRector, target PHP >= 7.0) encounters an ereg-family call whose literal pattern begins with or contains a bare quantifier, e.g. `ereg('*abc', $s)`, `split('a|+b', $s)`, or `ereg('a**', $s)` where the second '*' is parsed as a new atom. The atom loop sees '*', '+' or '?' where an atom is required and throws with the offending character in the message.

Common situations: Legacy grep/sed-style patterns pasted into ereg calls where a leading '*' was 'grep-ish' habit; broken edits that deleted the atom but kept the quantifier; glob-like patterns ('*.txt') mistakenly used as regexes in split()/ereg().

Related errors


AI-assisted analysis of rectorphp/rector@408fcb0ff1 (2026-08-21). Data as JSON: /api/errors/50048422e3e6b453. Report an issue: GitHub.