rectorphp/rector · error · ShouldNotHappenException

Rector name cannot be empty

Error message

Rector name cannot be empty

What it means

The custom-rule console command interactively asks for the rule class name using SymfonyStyle::ask() with a validator closure. The closure throws ShouldNotHappenException('Rector name cannot be empty') when the answer is null (Ctrl+C style abort) or an empty string, so the scaffold command refuses to generate files for an unnamed rule.

Source

Thrown at src/Console/Command/CustomRuleCommand.php:44

     */
    private ReflectionProvider $reflectionProvider;
    public function __construct(SymfonyStyle $symfonyStyle, ReflectionProvider $reflectionProvider)
    {
        $this->symfonyStyle = $symfonyStyle;
        $this->reflectionProvider = $reflectionProvider;
        parent::__construct();
    }
    protected function configure(): void
    {
        $this->setName('custom-rule');
        $this->setDescription('Create base of local custom rule with tests');
    }
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // ask for rule name
        $rectorName = $this->symfonyStyle->ask('What is the rule class name? (e.g. "LegacyCallToDbalMethodCall")?', null, static function (?string $answer): string {
            if ($answer === '' || $answer === null) {
                throw new ShouldNotHappenException('Rector name cannot be empty');
            }
            return $answer;
        });
        // suffix with Rector by convention
        if (substr_compare((string) $rectorName, 'Rector', -strlen('Rector')) !== 0) {
            $rectorName .= 'Rector';
        }
        $rectorName = ucfirst((string) $rectorName);
        // find all files in templates directory
        $finder = Finder::create()->files()->in(__DIR__ . '/../../../templates/custom-rule')->notName('__Name__Test.php.phtml');
        // 0. resolve if local phpunit is at least PHPUnit 10 (which supports #[DataProvider])
        // to provide annotation if not
        if ($this->isPHPUnitAttributeSupported()) {
            $finder->append([new SplFileInfo(__DIR__ . '/../../../templates/custom-rule/utils/rector/tests/Rector/__Name__/__Name__Test.php.phtml', 'utils/rector/tests/Rector/__Name__', 'utils/rector/tests/Rector/__Name__/__Name__Test.php.phtml')]);
        } else {
            // use @annotations for PHPUnit 9 and bellow
            $finder->append([new SplFileInfo(__DIR__ . '/../../../templates/custom-rules-annotations/utils/rector/tests/Rector/__Name__/__Name__Test.php.phtml', 'utils/rector/tests/Rector/__Name__', 'utils/rector/tests/Rector/__Name__/__Name__Test.php.phtml')]);
        }

View on GitHub (pinned to 408fcb0ff1)

Solutions

  1. Re-run vendor/bin/rector custom-rule and type a non-empty class name, e.g. LegacyCallToDbalMethodCall (the 'Rector' suffix is appended automatically if missing)
  2. When scripting, pipe the name in: echo 'MyRule' | vendor/bin/rector custom-rule
  3. Do not abort at the prompt with empty input; use Ctrl+C to cancel intentionally

Example fix

// before (interactive session)
$ vendor/bin/rector custom-rule
What is the rule class name? => <Enter>   // throws

// after
$ vendor/bin/rector custom-rule
What is the rule class name? => LegacyCallToDbalMethodCall
Defensive patterns

Strategy: validation

Validate before calling

// pre-validate before driving the command non-interactively
$ruleName = trim((string) $input->getOption('rule-name'));
if ($ruleName === '') {
    throw new RuntimeException('Rule name is required when running custom-rule non-interactively.');
}
shell_exec(sprintf('echo %s | vendor/bin/rector custom-rule', escapeshellarg($ruleName)));

Type guard

function isValidRuleClassName(string $name): bool
{
    return preg_match('/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$/', $name) === 1;
}

Prevention

When it happens

Trigger: Running vendor/bin/rector custom-rule and pressing Enter on the 'What is the rule class name?' prompt without typing anything; or piping empty stdin in a non-interactive script.

Common situations: Running the command in CI or a scripted pipeline with no TTY where ask() receives empty input; accidentally hitting Enter twice; automating scaffolds with expect and mis-timing the answer.

Related errors


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