Repository navigation
Description
Summary
The template's root composer.json pins phpstan/phpstan to <=2.3.3 as a stopgap. With PHPStan 2.3.4, Rector crashes on every file, so ahoy lint fails on any fresh install. The pin needs to come off once the upstream fixes land, otherwise consumer sites stay stuck on an old PHPStan.
Details
Why Rector breaks
PHPStan 2.3.4 (released 2026-10-28) moved to phpstan/phpdoc-parser 2.4.0, which adds FullyQualifiedNameNode and lets CallableTypeNode accept it. ClosureType::toPhpDocNode() inside the PHPStan phar now builds a CallableTypeNode with one.
Rector ships its own unprefixed copy of phpdoc-parser (2.3.x) in vendor/rector/rector/vendor, and that copy gets autoloaded first. PHPStan's code then calls the old constructor:
[ERROR] Could not process "web/modules/custom/ys_base/tests/src/Kernel/ExampleTest.php" file, due to:
"System error: "PHPStan\PhpDocParser\Ast\Type\CallableTypeNode::__construct(): Argument #1 ($identifier)
must be of type PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode,
PHPStan\PhpDocParser\Ast\Type\FullyQualifiedNameNode given,
called in phar://vendor/phpstan/phpstan/phpstan.phar/src/Type/ClosureType.php:759"
PHPStan's own analysis still passes. Only Rector, which runs PHPStan in-process, fails. Every released Rector version is affected, including the latest, 2.8.2.
Why upgrading Rector isn't enough
Vortex can't move past Rector 2.6.1 anyway: palantirnet/drupal-rector 1.1.3 declares conflict: rector/rector >=2.6.2, because Rector 2.6.2 removed PHPUnitSetList, which drupal-rector's set lists depend on.
Upstream blockers
Both have to land and be released before the pin can go:
- Rector: Rector 2.8.2 + PHPStan 2.3.4: CallableTypeNode::__construct() expects IdentifierTypeNode, FullyQualifiedNameNode given (bundled phpdoc-parser 2.3.11) rectorphp/rector#9947 - fix in Bump PHPStan to 2.3.4 and phpdoc-parser to 2.4 rectorphp/rector-src#8883 (bumps the bundled
phpdoc-parserto 2.4). - drupal-rector: rector 2.6.2+ breaks Drupal*SetList because PHPUnitSetList was removed palantirnet/drupal-rector#420 - fix in feat: add composer-based set binding every rule to an exact drupal/core version palantirnet/drupal-rector#419 (open, no review since early October).
Done when
- A
palantirnet/drupal-rectorrelease allows a Rector version whose bundledphpdoc-parseris 2.4 or newer. phpstan/phpstanin the rootcomposer.jsongoes back to a caret constraint (^2.3.4or higher).ahoy lintpasses with Rector on a fresh install.
Note on the constraint form
The pin is <=2.3.3 rather than ^2.3.1 <2.3.4 because the installer's snapshot normaliser only collapses single-token constraints to __VERSION__. A 2-part range would change every installer fixture. A plain caret constraint is fine when the pin is removed, so no snapshot refresh is needed.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsBACKLOG
Activity
AlexSkrypnyk commentedon Oct 29, 2026
Status as of 2026-10-30: half unblocked.
palantirnet/drupal-rector1.1.3 (still the latest release) keepsconflict: rector/rector >=2.6.2, so Vortex keeps resolving Rector 2.6.1, which can't use the fix.Verified locally: with the pin removed, Composer resolves PHPStan 2.3.4 but leaves Rector on 2.6.1. A cache-cleared
rector --dry-runthen fails on every file with the sameCallableTypeNode::__construct()error. With the pin in place, the same cache-cleared run passes on all 64 files.Watch out when checking this: a plain
ahoy lint-becan pass with the pin removed, because Rector's result cache skips files that passed under 2.3.3. CI has no cache, so test with--clear-cache.Next step: once a drupal-rector release allows Rector 2.8.3 or later, set
phpstan/phpstanback to^2.3.4and run a cache-cleared Rector to confirm.