rectorphp/rector · error · ShouldNotHappenException

"%s" rule is deprecated, as the scalar value target is too w

Error message

"%s" rule is deprecated, as the scalar value target is too wide and replaces values in unrelated contexts; use a custom rule scoped to the exact context instead

What it means

Rector\Transform\Rector\Scalar\ScalarValueToConstFetchRector is deprecated: refactor() throws Rector\Exception\ShouldNotHappenException on the first String_, Float_ or Int_ literal. The rule replaced configured scalar values (e.g. the int 10 with SomeClass::FOOBAR_INT), but a bare literal target is too wide - the same number or string appears in unrelated contexts, so the rewrite corrupts unrelated code. configure() is an empty no-op, so old value mappings are ignored before the throw.

Source

Thrown at rules/Transform/Rector/Scalar/ScalarValueToConstFetchRector.php:46

        return new RuleDefinition('Replaces Scalar values with a ConstFetch or ClassConstFetch', [new ConfiguredCodeSample(<<<'SAMPLE'
$var = 10;
SAMPLE
, <<<'SAMPLE'
$var = \SomeClass::FOOBAR_INT;
SAMPLE
, [new ScalarValueToConstFetch(new Int_(10), new ClassConstFetch(new FullyQualified('SomeClass'), new Identifier('FOOBAR_INT')))])]);
    }
    public function getNodeTypes(): array
    {
        return [String_::class, Float_::class, Int_::class];
    }
    /**
     * @param String_|Float_|Int_ $node
     * @return \PhpParser\Node\Expr\ConstFetch|\PhpParser\Node\Expr\ClassConstFetch|null
     */
    public function refactor(Node $node)
    {
        throw new ShouldNotHappenException(sprintf('"%s" rule is deprecated, as the scalar value target is too wide and replaces values in unrelated contexts; use a custom rule scoped to the exact context instead', self::class));
    }
    /**
     * @param mixed[] $configuration
     */
    public function configure(array $configuration): void
    {
    }
}

View on GitHub (pinned to 408fcb0ff1)

Solutions

  1. Remove ScalarValueToConstFetchRector from rector.php.
  2. Replace the meaningful literals manually with the intended class constant / const fetch, reviewing each context.
  3. If automation is needed, write a custom rule that matches the literal only in the exact contexts (specific methods/classes) where the constant applies.

Example fix

// before (rector.php)
->withConfiguredRule(ScalarValueToConstFetchRector::class, [
    new ScalarValueToConstFetch(new Int_(10), new ClassConstFetch(new FullyQualified('SomeClass'), new Identifier('FOOBAR_INT'))),
])

// after (rector.php) - removed

// before            // after
$limit = 10;         $limit = SomeClass::FOOBAR_INT;
Defensive patterns

Strategy: validation

Validate before calling

use Rector\Transform\Rector\Scalar\ScalarValueToConstFetchRector;

$rules = [/* your list */ ScalarValueToConstFetchRector::class];
if (in_array(ScalarValueToConstFetchRector::class, $rules, true)) {
    throw new InvalidArgumentException('Rule deprecated; replace literals manually or with a context-scoped custom rule');
}

Try / catch

try {
    exit($rectorApplication->run());
} catch (\Rector\Exception\ShouldNotHappenException $e) {
    if (str_contains($e->getMessage(), 'ScalarValueToConstFetchRector')) {
        fwrite(STDERR, 'Remove the rule; bare-scalar matches hit unrelated contexts.' . PHP_EOL);
        exit(1);
    }
    throw $e;
}

Prevention

When it happens

Trigger: The rule is still referenced in rector.php (withRules() or withConfiguredRule() with an old scalar=>const map, as in the rule's configured code sample) and rector visits any string/float/int literal; refactor() throws on the first literal.

Common situations: Configs that centralized 'magic numbers' via rector; rector upgrade breaking CI at the first literal encountered; users assuming their old value mapping still protects them because no config error appears.

Related errors


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