rectorphp/rector · error · ShouldNotHappenException
Matching file paths by using glob-patterns is no longer supp
Error message
Matching file paths by using glob-patterns is no longer supported. Use specific file path instead.
What it means
RectorConfig::import() loads another config file and executes its returned closure; glob/wildcard imports were removed, so it rejects any path that both fails realpath() and contains '*' with ShouldNotHappenException (see upstream issue #9156). The message tells you to import concrete files instead. Every other file type still works -- only wildcard patterns are refused.
Source
Thrown at src/Config/RectorConfig.php:239
$this->import($configFile);
}
}
/**
* @param class-string<Command> $commandClass
*/
public function command(string $commandClass): void
{
$this->singleton($commandClass);
$this->tag($commandClass, Command::class);
}
public function import(string $filePath): void
{
/**
* Only stop when filePath realpath is false and contains glob patterns
* @see https://github.com/rectorphp/rector/issues/9156#issuecomment-2869130541
*/
if (realpath($filePath) === \false && strpos($filePath, '*') !== \false) {
throw new ShouldNotHappenException('Matching file paths by using glob-patterns is no longer supported. Use specific file path instead.');
}
Assert::fileExists($filePath);
$self = $this;
$callable = require $filePath;
Assert::isCallable($callable);
/** @var callable(Container $container): void $callable */
$callable($self);
}
/**
* @param array<class-string<RectorInterface>> $rectorClasses
*/
public function rules(array $rectorClasses): void
{
Assert::allString($rectorClasses);
RectorConfigValidator::ensureNoDuplicatedClasses($rectorClasses);
foreach ($rectorClasses as $rectorClass) {
$this->rule($rectorClass);
}View on GitHub (pinned to 408fcb0ff1)
Solutions
- Import each file explicitly: ->import(__DIR__ . '/config/early.php')
- Or expand the glob yourself and import every existing file (see example)
- Prefer native builder composition: put shared rules in a class or use ->withSets()/->import() on concrete files
Example fix
// before
return RectorConfig::configure()
->import(__DIR__ . '/config/*.php');
// after
$rectorConfig = RectorConfig::configure();
foreach (glob(__DIR__ . '/config/*.php') as $configFile) {
$rectorConfig->import($configFile);
} Defensive patterns
Strategy: validation
Validate before calling
// expand globs yourself so only concrete files reach import()
$configFiles = glob(__DIR__ . '/config/*.php') ?: [];
foreach ($configFiles as $configFile) {
if (! is_file($configFile)) {
throw new InvalidArgumentException('Config file vanished: ' . $configFile);
}
$rectorConfig->import($configFile);
} Type guard
function isImportableConfigFile(string $path): bool
{
return strpos($path, '*') === false && is_file($path);
} Prevention
- Never put '*' in paths passed to ->import(); Rector rejects them by design
- List sub-configs explicitly for discoverability, or loop over glob() results yourself
- Remember only wildcard paths are rejected -- plain missing files still fail with Assert::fileExists()
When it happens
Trigger: Writing ->import(__DIR__ . '/config/*.php') or ->import(__DIR__ . '/sets/*.php') inside rector.php so multiple sub-configs can be pulled in at once.
Common situations: Configs migrated from other tools (PHPStan/ ECS) or older conventions that allowed glob imports; monorepos trying to auto-discover per-package rule files.
Related errors
- "%s" rule is deprecated, as inverting nested ifs to early re
- "%s" rule is deprecated, as splitting a single condition int
- "%s" rule is deprecated, as splitting a single return into m
- "%s" is deprecated as risky change with little value. Use ma
- Bootstrap file "%s" does not exist.
AI-assisted analysis of rectorphp/rector@408fcb0ff1 (2026-08-21).
Data as JSON: /api/errors/9f168f8c9ffb1b16.
Report an issue: GitHub.