rectorphp/rector · error · InvalidEregException

an invalid escape sequence at the end

Error message

an invalid escape sequence at the end

What it means

The ERE pattern being converted to PCRE ends with a lone backslash (EregToPcreTransformer.php:148). A trailing '\' opens an escape sequence but has nothing to escape, which is invalid in POSIX ERE, so EregToPcreTransformer throws InvalidEregException and the ereg-to-preg rewrite of that call aborts.

Source

Thrown at rules/Php70/EregToPcreTransformer.php:148

                    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;
                ++$i;
                continue;
            } elseif ($char === '\\') {
                if (++$i >= $l) {
                    throw new InvalidEregException('an invalid escape sequence at the end');
                }
                $r[$rr] .= $this->_ere2pcre_escape($content[$i]);
            } else {
                // including ] and } which are allowed as a literal character
                $r[$rr] .= $this->_ere2pcre_escape($char);
            }
            ++$i;
            if ($i >= $l) {
                break;
            }
            // piece after the atom (only ONE of them is possible)
            $char = $content[$i];
            if (in_array($char, ['*', '+', '?'], \true)) {
                $r[$rr] .= $char;
                ++$i;
            } elseif ($char === '{') {
                $i = (int) $i;
                $i = $this->processCurlyBracket($content, $i, $r, $rr);

View on GitHub (pinned to 408fcb0ff1)

Solutions

  1. Fix the literal in the file Rector reported: double the trailing backslash so it becomes an escaped literal '\\\\' (ERE for one literal backslash), or drop it if it was accidental.
  2. Re-run rector to confirm the ereg call now converts to preg_match cleanly.
  3. In bulk migrations, grep ereg/split string literals for patterns ending with an odd number of backslashes first.

Example fix

// before - pattern ends with lone backslash (PHP string 'C:\\path\\' => C:\path\)
ereg('C:\\path\\', $subject);

// after - trailing backslash escaped
ereg('C:\\path\\\\\\\\', $subject);
Defensive patterns

Strategy: try-catch

Validate before calling

// quick lint: pattern ends with an odd run of backslashes
function endsInLoneBackslash(string $p): bool {
    $n = 0; $i = strlen($p) - 1;
    while ($i >= 0 && $p[$i] === '\\') { $n++; $i--; }
    return $n % 2 === 1;
}

Try / catch

try {
    $pcre = $eregToPcreTransformer->transform($pattern, $ignoreCase);
} catch (InvalidEregException $e) {
    // trailing escape with nothing to escape — double or drop the final backslash
    continue;
}

Prevention

When it happens

Trigger: Rector (Php70 set / EregToPregMatchRector, target PHP >= 7.0) visits an ereg-family call whose first argument is a string literal ending in a backslash. Note PHP string semantics: "abc\\" in source is the 4-char pattern abc\ and triggers it; 'C:\path\' with a real trailing backslash also does. After the '\' branch does ++$i >= $l, the exception 'an invalid escape sequence at the end' is thrown.

Common situations: Windows path or DOS-prefix patterns ('C:\\') where the final backslash was meant literally but never doubled; patterns chopped by an edit so the escaped character after '\' was lost; PHP single-quoted strings where the author did not realize a trailing '\' is a literal backslash that ERE cannot carry at the end.

Related errors


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