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\Php85\Rector\Const_\ConstAndTraitDeprecatedAttributeRector is deprecated: refactor() throws Rector\Exception\ShouldNotHappenException on the first Const_ or Trait_ node. Like its PHP 8.4 sibling (DeprecatedAnnotationToDeprecatedAttributeRector), it converted the passive @deprecated annotation into #[Deprecated], but the attribute emits a real runtime deprecation notice - an unintended behavior change. Use phpstan/phpstan-deprecation-rules to report the annotation during static analysis instead.

Source

Thrown at rules/Php85/Rector/Const_/ConstAndTraitDeprecatedAttributeRector.php:44

 */
const SomeConstant = 'irrelevant';
CODE_SAMPLE
, <<<'CODE_SAMPLE'
#[\Deprecated(message: 'Use SomeOtherConstant instead', since: '1.0.0')]
const SomeConstant = 'irrelevant';
CODE_SAMPLE
)]);
    }
    public function getNodeTypes(): array
    {
        return [Const_::class, Trait_::class];
    }
    /**
     * @param Const_|Trait_ $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 PhpVersion::PHP_85;
    }
}

View on GitHub (pinned to 408fcb0ff1)

Solutions

  1. Remove ConstAndTraitDeprecatedAttributeRector from rector.php.
  2. Keep @deprecated annotations on constants/traits and report their usage via phpstan/phpstan-deprecation-rules.
  3. Add #[Deprecated] manually only where a runtime notice is deliberately desired.

Example fix

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

// after (rector.php) - removed; keep annotations, check statically
// composer require --dev phpstan/phpstan-deprecation-rules
Defensive patterns

Strategy: validation

Validate before calling

use Rector\Php85\Rector\Const_\ConstAndTraitDeprecatedAttributeRector;

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

Try / catch

try {
    exit($rectorApplication->run());
} catch (\Rector\Exception\ShouldNotHappenException $e) {
    if (str_contains($e->getMessage(), 'ConstAndTraitDeprecatedAttributeRector')) {
        fwrite(STDERR, 'Remove the rule; #[Deprecated] on consts/traits fires runtime notices - report statically instead.' . PHP_EOL);
        exit(1);
    }
    throw $e;
}

Prevention

When it happens

Trigger: The rule is still present in a PHP 8.5 upgrade config and rector visits any const statement (class const or top-level const) or trait declaration; refactor() throws on the first match.

Common situations: Running a copied withPhp85() era config after the rule was gutted; CI failing immediately after `composer update rector/rector`; enabling every Php85 rule wholesale to 'modernize' a codebase.

Related errors


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