rectorphp/rector · error · ShouldNotHappenException

"%s" rule is deprecated, as the #[Deprecated] attribute trig

Error message

"%s" rule is deprecated, as the #[Deprecated] attribute triggers a runtime deprecation, unlike the @deprecated annotation; use "phpstan/phpstan-deprecation-rules" to report the annotation instead

What it means

Rector\Php84\Rector\Class_\DeprecatedAnnotationToDeprecatedAttributeRector is deprecated: refactor() throws Rector\Exception\ShouldNotHappenException on the first Function_, ClassMethod or ClassConst node. The rule converted the passive @deprecated docblock annotation into the native #[Deprecated] attribute, but unlike the annotation the attribute triggers a real runtime deprecation notice whenever the element is called - a behavior change rector should not automate. The recommended replacement is the static-analysis package phpstan/phpstan-deprecation-rules, which reports @deprecated usage without runtime effects.

Source

Thrown at rules/Php84/Rector/Class_/DeprecatedAnnotationToDeprecatedAttributeRector.php:49

CODE_SAMPLE
, <<<'CODE_SAMPLE'
#[\Deprecated(message: 'Use SomeOtherFunction instead', since: '1.0.0')]
function someFunction()
{
}
CODE_SAMPLE
)]);
    }
    public function getNodeTypes(): array
    {
        return [Function_::class, ClassMethod::class, ClassConst::class];
    }
    /**
     * @param ClassConst|Function_|ClassMethod $node
     */
    public function refactor(Node $node): ?Node
    {
        throw new ShouldNotHappenException(sprintf('"%s" rule is deprecated, as the #[Deprecated] attribute triggers a runtime deprecation, unlike the @deprecated annotation; use "phpstan/phpstan-deprecation-rules" to report the annotation instead', self::class));
    }
    public function provideMinPhpVersion(): int
    {
        return PhpVersionFeature::DEPRECATED_ATTRIBUTE;
    }
}

View on GitHub (pinned to 408fcb0ff1)

Solutions

  1. Remove DeprecatedAnnotationToDeprecatedAttributeRector from rector.php.
  2. Keep the @deprecated annotation and install phpstan/phpstan-deprecation-rules so PHPStan reports calls to deprecated code during static analysis.
  3. Only add #[Deprecated] by hand on the rare element where a runtime notice is explicitly wanted.

Example fix

// before (rector.php)
->withRules([
    DeprecatedAnnotationToDeprecatedAttributeRector::class,
])

// after (rector.php) - rule removed; keep the annotation and check it statically
/**
 * @deprecated use Mailer::send() instead
 */
// composer require --dev phpstan/phpstan-deprecation-rules
Defensive patterns

Strategy: validation

Validate before calling

use Rector\Php84\Rector\Class_\DeprecatedAnnotationToDeprecatedAttributeRector;

$rules = [/* your list */ DeprecatedAnnotationToDeprecatedAttributeRector::class];
if (in_array(DeprecatedAnnotationToDeprecatedAttributeRector::class, $rules, true)) {
    throw new InvalidArgumentException('Rule deprecated; use phpstan/phpstan-deprecation-rules instead');
}

Try / catch

try {
    exit($rectorApplication->run());
} catch (\Rector\Exception\ShouldNotHappenException $e) {
    if (str_contains($e->getMessage(), 'DeprecatedAnnotationToDeprecatedAttributeRector')) {
        fwrite(STDERR, 'Remove the rule; keep @deprecated and report usage via phpstan/phpstan-deprecation-rules.' . PHP_EOL);
        exit(1);
    }
    throw $e;
}

Prevention

When it happens

Trigger: The rule remains in rector.php (directly or copied from an old PHP 8.4 upgrade config) and rector visits any function, class method or class constant; refactor() throws on the first match.

Common situations: Running a PHP 8.4 level/set config built before the deprecation; CI failing right after a rector upgrade; teams wanting 'deprecated' warnings in CI without changing runtime behavior.

Related errors


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