rectorphp/rector · error · ShouldNotHappenException
"%s" rule is deprecated, as it creates unreadable code with
Error message
"%s" rule is deprecated, as it creates unreadable code with messy checks; refactor the value to a sole type instead
What it means
Rector\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector is deprecated: refactor() throws Rector\Exception\ShouldNotHappenException on the first Empty_ or BooleanNot node. The rule tried to satisfy the strict/rule 'no empty()' policy by replacing empty()/!empty() with explicit type checks, but the generated comparisons were messy and hard to read. The accepted answer is to refactor the value so it has a single unambiguous type, after which a plain comparison replaces empty().
Source
Thrown at rules/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector.php:65
return $items === [];
}
}
CODE_SAMPLE
, [self::TREAT_AS_NON_EMPTY => \false])]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Empty_::class, BooleanNot::class];
}
/**
* @param Empty_|BooleanNot $node
*/
public function refactor(Node $node): ?Node
{
throw new ShouldNotHappenException(sprintf('"%s" rule is deprecated, as it creates unreadable code with messy checks; refactor the value to a sole type instead', self::class));
}
}
View on GitHub (pinned to 408fcb0ff1)
Solutions
- Remove DisallowedEmptyRuleFixerRector from rector.php.
- Refactor the offending value to a single concrete type (e.g. always an array), then replace empty($x) with an explicit comparison like $x === [].
- Enforce the 'no empty()' policy in code review or a sniff that only reports, instead of an automated rewrite.
Example fix
// before (rector.php)
->withRules([DisallowedEmptyRuleFixerRector::class])
// after (rector.php) - removed; fix types by hand
// before
if (empty($items)) {
return [];
}
// after - $items is guaranteed to be an array
if ($items === []) {
return [];
} Defensive patterns
Strategy: validation
Validate before calling
use Rector\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector;
$rules = [/* your list */ DisallowedEmptyRuleFixerRector::class];
if (in_array(DisallowedEmptyRuleFixerRector::class, $rules, true)) {
throw new InvalidArgumentException('Rule deprecated; refactor the value to a sole type instead of rewriting empty()');
} Try / catch
try {
exit($rectorApplication->run());
} catch (\Rector\Exception\ShouldNotHappenException $e) {
if (str_contains($e->getMessage(), 'DisallowedEmptyRuleFixerRector')) {
fwrite(STDERR, 'Remove the rule; fix variable types so empty() can become an explicit comparison.' . PHP_EOL);
exit(1);
}
throw $e;
} Prevention
- Enforce 'no empty()' with a detector (slevomat coding standard sniff) that only reports, instead of an automated rewriter.
- Narrow variable types first (PHPStan), then replace empty() manually with the exact comparison.
- After rector upgrades, remove 'strict' bundle rules that now throw instead of rewriting.
When it happens
Trigger: The rule is listed in rector.php (often via an old custom 'strict' rule list) and the analyzed code contains empty(...) or !empty(...) or negated expressions; refactor() throws on the first Empty_/BooleanNot match.
Common situations: Enabling a copied 'strict' rule bundle after a rector upgrade; CI failing as soon as it scans a file using empty(); teams trying to ban empty() project-wide via rector.
Related errors
- "%s" rule is deprecated, as turning a docblock type into a r
- "%s" rule is deprecated, as risky. The "??" and "?:" operato
- "%s" is deprecated as depends on context and personal prefer
- "%s" rule is deprecated, as it is a personal preference that
- "%s" is deprecated, as simplifying regex ranges is a persona
AI-assisted analysis of rectorphp/rector@408fcb0ff1 (2026-08-21).
Data as JSON: /api/errors/66f79ef4eeaa6cbe.
Report an issue: GitHub.