rectorphp/rector · error · ShouldNotHappenException
"%s" rule is deprecated, as inverting nested ifs to early re
Error message
"%s" rule is deprecated, as inverting nested ifs to early return makes the code harder to read and understand
What it means
This exception is thrown by Rector when the deprecated ChangeNestedIfsToEarlyReturnRector rule actually runs. The rule class still exists so old configs keep loading, but its refactor() method unconditionally throws ShouldNotHappenException: inverting nested ifs into early returns was judged to make code harder to read, so the transformation is intentionally dead. Hitting it means your configuration still registers a rule that no longer performs any work.
Source
Thrown at rules/EarlyReturn/Rector/If_/ChangeNestedIfsToEarlyReturnRector.php:63
return 'yes';
}
return 'no';
}
}
CODE_SAMPLE
)]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return NodeGroup::STMTS_AWARE;
}
public function refactor(Node $node): ?Node
{
throw new ShouldNotHappenException(sprintf('"%s" rule is deprecated, as inverting nested ifs to early return makes the code harder to read and understand', self::class));
}
}
View on GitHub (pinned to 408fcb0ff1)
Solutions
- Remove the `ChangeNestedIfsToEarlyReturnRector::class` registration line from your rector.php/rector.yml and re-run.
- Search the whole config for other EarlyReturn rules (ChangeOrIfContinueToMultiContinueRector, ReturnBinaryOrToEarlyReturnRector) and deprecated rules in general; remove them in the same pass.
- If you truly want nested-if inversion, write the transformation manually or in a custom rule in your project, as the exception message itself advises.
- If removal is not immediately possible, pin the last Rector version where the rule still transformed code, and schedule the config cleanup.
Example fix
// before - rector.php $rectorConfig->rule(\Rector\EarlyReturn\Rector\If_\ChangeNestedIfsToEarlyReturnRector::class); // after - rule removed; invert nested ifs manually or in a custom rule // (no registration)
Defensive patterns
Strategy: validation
Validate before calling
// before running rector, assert the deprecated rule is not registered
$config = file_get_contents('rector.php');
if (strpos($config, 'ChangeNestedIfsToEarlyReturnRector') !== false) {
exit("Remove deprecated ChangeNestedIfsToEarlyReturnRector from rector.php before running rector.\n");
} Prevention
- Do not enumerate individual rules in rector.php; prefer version sets (e.g. ->sets([LevelSetList::UP_TO_PHP_XX])) so deprecated rules drop out automatically.
- After every rector/rector major upgrade, run `vendor/bin/rector list` (or check its changelog) for rules marked DeprecatedInterface and prune your config.
- Keep rector config under review in CI with a lint that greps for 'Deprecated' rule classes.
When it happens
Trigger: Running `rector process` on a config (rector.php/rector.yml) that contains `$rectorConfig->rule(\Rector\EarlyReturn\Rector\If_\ChangeNestedIfsToEarlyReturnRector::class)` (or a set/import that pulls it in). The throw fires as soon as the rule visits any statements-aware node (NodeGroup::STMTS_AWARE: functions, methods, ifs, loops, etc.), which on a real codebase is immediately.
Common situations: Teams upgrading Rector across major versions while keeping an old rector.php that explicitly listed EarlyReturn rules; configs copied from outdated blog posts or inherited projects; CI suddenly failing after a `composer update rector/rector` because the rule throwing replaced the old behavior silently.
Related errors
- "%s" rule is deprecated, as splitting a single condition int
- "%s" rule is deprecated, as splitting a single return into m
- "%s" is deprecated as risky change with little value. Use ma
- "%s" rule is deprecated, as turning a docblock type into a r
- "%s" rule is deprecated, as risky. The "??" and "?:" operato
AI-assisted analysis of rectorphp/rector@408fcb0ff1 (2026-08-21).
Data as JSON: /api/errors/1fc59e935471cb8f.
Report an issue: GitHub.