rectorphp/rector · error · ShouldNotHappenException

"%s" is deprecated, as it copies docblock from another metho

Error message

"%s" is deprecated, as it copies docblock from another method call that can be incorrect or outdated

What it means

Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector is deprecated: refactor() throws Rector\Exception\ShouldNotHappenException on the first ClassMethod node. The rule copied the @return docblock from another method call (e.g. the create() call inside the body) onto the enclosing method, but a copied docblock can be incorrect for the wrapper or become outdated when the inner method changes.

Source

Thrown at rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddReturnDocblockFromMethodCallDocblockRector.php:77

        // ...
    }
}
CODE_SAMPLE
)]);
    }
    /**
     * @return array<class-string<Node>>
     */
    public function getNodeTypes(): array
    {
        return [ClassMethod::class];
    }
    /**
     * @param ClassMethod $node
     */
    public function refactor(Node $node): ?Node
    {
        throw new ShouldNotHappenException(sprintf('"%s" is deprecated, as it copies docblock from another method call that can be incorrect or outdated', self::class));
    }
}

View on GitHub (pinned to 408fcb0ff1)

Solutions

  1. Remove AddReturnDocblockFromMethodCallDocblockRector from rector.php.
  2. Add the @return docblock manually where the wrapper's return type is genuinely the same, and keep it in sync on changes.
  3. Better: add a native return type or delegate the type via PHPStan generics instead of copying docblocks.

Example fix

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

// after (rector.php) - removed; write by hand

/**
 * @return array<int, Item>
 */
public function createAll(): array
Defensive patterns

Strategy: validation

Validate before calling

use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector;

$rules = [/* your list */ AddReturnDocblockFromMethodCallDocblockRector::class];
if (in_array(AddReturnDocblockFromMethodCallDocblockRector::class, $rules, true)) {
    throw new InvalidArgumentException('Rule deprecated; do not copy docblocks between methods automatically');
}

Try / catch

try {
    exit($rectorApplication->run());
} catch (\Rector\Exception\ShouldNotHappenException $e) {
    if (str_contains($e->getMessage(), 'AddReturnDocblockFromMethodCallDocblockRector')) {
        fwrite(STDERR, 'Remove the rule; copied docblocks drift from the inner method.' . PHP_EOL);
        exit(1);
    }
    throw $e;
}

Prevention

When it happens

Trigger: The rule is still listed in a TypeDeclarationDocblocks rule list and rector visits any class method; refactor() throws on the first ClassMethod match.

Common situations: Static-analysis coverage pushes that added docblocks everywhere; CI failing at the first factory-style method after a rector upgrade; docblocks drifting out of sync with the copied source method.

Related errors


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