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

  1. Remove DisallowedEmptyRuleFixerRector from rector.php.
  2. Refactor the offending value to a single concrete type (e.g. always an array), then replace empty($x) with an explicit comparison like $x === [].
  3. 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

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


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