rectorphp/rector · error · ShouldNotHappenException

"%s" is deprecated as depends on context and personal prefer

Error message

"%s" is deprecated as depends on context and personal preference, hard to generalize. Handle it manually or via a custom rule instead

What it means

JoinStringConcatRector used to merge chained string concatenations like 'a' . 'b' . $c into fewer parts. It is deprecated because whether joined strings read better is a matter of context and personal taste that cannot be generalized, so refactor() now throws ShouldNotHappenException for every Concat node. The rule performs no work anymore; the exception exists purely to make stale configs fail fast.

Source

Thrown at rules/CodeQuality/Rector/Concat/JoinStringConcatRector.php:52

        $name = 'Hi Tom';
    }
}
CODE_SAMPLE
)]);
    }
    /**
     * @return array<class-string<Node>>
     */
    public function getNodeTypes(): array
    {
        return [Concat::class];
    }
    /**
     * @param Concat $node
     */
    public function refactor(Node $node): ?Node
    {
        throw new ShouldNotHappenException(sprintf('"%s" is deprecated as depends on context and personal preference, hard to generalize. Handle it manually or via a custom rule instead', self::class));
    }
}

View on GitHub (pinned to 408fcb0ff1)

Solutions

  1. Remove JoinStringConcatRector::class from rector.php and any imported set files, then re-run vendor/bin/rector dry-run
  2. If you want constant-string folding, handle the few occurrences manually or with a targeted script
  3. If join style matters to your team, encode it in a coding-standard tool (PHP-CS-Fixer) rather than Rector
  4. grep -r JoinStringConcatRector across the project to find every registration point

Example fix

// before (rector.php)
->withRules([
    \Rector\CodeQuality\Rector\Concat\JoinStringConcatRector::class,
])

// after
->withRules([
    // keep only non-deprecated CodeQuality rules here
])
// manually: echo 'Hello' . ' ' . 'world';  ->  echo 'Hello world';
Defensive patterns

Strategy: validation

Validate before calling

$deprecated = ['JoinStringConcatRector'];
foreach (glob(__DIR__ . '/rector*.php') as $config) {
    $src = file_get_contents($config);
    foreach ($deprecated as $rule) {
        if (str_contains($src, $rule)) {
            fwrite(STDERR, "Remove deprecated rule {$rule} from {$config}\n");
            exit(1);
        }
    }
}

Prevention

When it happens

Trigger: Having rules/CodeQuality/Rector/Concat/JoinStringConcatRector.php registered (directly or via a set) and running rector over any file containing a string concatenation expression (. operator). The first Concat node visited triggers the throw at rules/CodeQuality/Rector/Concat/JoinStringConcatRector.php:52.

Common situations: An old rector.php with a hand-picked CodeQuality rule list, or a shared company-wide set package, still contains JoinStringConcatRector after upgrading Rector. The crash appears the moment dry-run touches any file with 'literal' . 'literal' concatenation, which is extremely common, so it fails almost immediately.

Related errors


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