rectorphp/rector · error · InvalidConfigurationException

Set provider " " must implement

Error message

Set provider "%s" must implement "%s"

What it means

RectorConfigBuilder::withSetProviders(string ...$setProviders) registers classes that supply extra rule sets. Each class-string is verified with is_a($setProvider, SetProviderInterface::class, true); a class that does not implement Rector\Set\SetProviderInterface throws InvalidConfigurationException naming the offending class and the required interface.

Solutions

  1. Open the class named in the message and make it implement Rector\Set\SetProviderInterface with a sets() method returning Rector\Set\ValueObject\Set[] instances
  2. Fix the namespace/typo so the string matches the real provider class
  3. If you meant a built-in set, use withSets([SomeSetList::CONSTANT]) instead of withSetProviders()
  4. Pass class-strings via SomeProvider::class, never literals or objects

Example fix

// before
return $this->withSetProviders('App\Support\ProjectSetList');

// after
final class ProjectSetProvider implements \Rector\Set\SetProviderInterface
{
    /**
     * @return Set[]
     */
    public function sets(): array
    {
        return [new Set('project-conventions', [SomeRule::class])];
    }
}

return $this->withSetProviders(ProjectSetProvider::class);
Defensive patterns

Strategy: type-guard

Type guard

/** @param class-string ...$providers */
function assertSetProviders(string ...$providers): void
{
    foreach ($providers as $provider) {
        if (! is_a($provider, \Rector\Set\SetProviderInterface::class, true)) {
            throw new InvalidArgumentException(sprintf('%s does not implement SetProviderInterface', $provider));
        }
    }
}

Try / catch

try {
    $builder->withSetProviders(ProjectSetProvider::class);
} catch (InvalidConfigurationException $e) {
    // message names the class and the interface; fix the class-string, not the call
    $logger->error($e->getMessage());
}

Prevention

When it happens

Trigger: Passing a FQCN that is not a SetProviderInterface implementation: a typo'd namespace, a plain value object, or a SetList constant instead of a provider class. Also triggered by passing a class that only extends a base class without implementing the interface.

Common situations: Copy-pasting a SetList:: constant into withSetProviders(); fat-fingered namespaces after renaming vendor packages; passing an instance or ::class of an unrelated helper while wiring custom sets.

Related errors


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

Appendix: source

Thrown at src/Configuration/RectorConfigBuilder.php:807

        $this->reportUnusedSkips = $report;
        return $this;
    }
    public function withEditorUrl(string $editorUrl): self
    {
        $this->editorUrl = $editorUrl;
        return $this;
    }
    /**
     * @param class-string<SetProviderInterface> ...$setProviders
     */
    public function withSetProviders(string ...$setProviders): self
    {
        foreach ($setProviders as $setProvider) {
            if (\array_key_exists($setProvider, $this->setProviders)) {
                continue;
            }
            if (!is_a($setProvider, SetProviderInterface::class, \true)) {
                throw new InvalidConfigurationException(sprintf('Set provider "%s" must implement "%s"', $setProvider, SetProviderInterface::class));
            }
            $this->setProviders[$setProvider] = \true;
        }
        return $this;
    }
    /**
     * @param PhpVersion::* $phpVersion
     */
    private function addPhpLevelSets(int $phpVersion): self
    {
        $this->isWithPhpSetsUsed = \true;
        $this->sets = array_merge($this->sets, \Rector\Configuration\PhpLevelSetResolver::resolveFromPhpVersion($phpVersion));
        return $this;
    }
    private function reportDeprecatedPhpSetsMethod(string $methodName): self
    {
        SimpleParameterProvider::addParameter(\Rector\Configuration\Option::DEPRECATED_PHP_SETS_METHODS, $methodName);
        return $this;

View on GitHub (pinned to 408fcb0ff1)