passbolt/passbolt_api · error · InternalErrorException

The class is not a valid plugin.

Error message

The class {$name} is not a valid plugin.

What it means

After confirming $name is a valid PluginInterface subclass, getPluginEnabledConfigurationKey() strips the namespace and the trailing 'Plugin' suffix (substr(..., 0, -6)) to derive the short plugin name. If the result is empty — meaning the class name itself is literally 'Plugin' or the extraction yields nothing — an InternalErrorException is thrown since no config key can be built.

Solutions

  1. Pass the concrete plugin class (e.g. \PassboltCe\Folders\FoldersPlugin) instead of a base/generic class named 'Plugin'.
  2. Pass the plain short plugin name string instead of a class name.
  3. Rename the class so it follows the '<Name>Plugin' convention with a non-empty short name.

Example fix

// before
$this->enableFeaturePlugin('\My\Namespace\Plugin'); // basename 'Plugin' -> empty short name
// after
$this->enableFeaturePlugin('\My\Namespace\MyFeaturePlugin');
Defensive patterns

Strategy: validation

Validate before calling

$short = substr(strrchr($plugin, '\\') ?: $plugin, 1);
if ($short === '' || $short === 'Plugin') {
    throw new \InvalidArgumentException("$plugin is not a concrete plugin class");
}

Try / catch

try {
    $this->enableFeaturePlugin($plugin);
} catch (\Cake\Http\Exception\InternalErrorException $e) {
    if (str_contains($e->getMessage(), 'is not a valid plugin')) {
        Log::error('Plugin class name yields empty short name: ' . $plugin);
    }
    throw $e;
}

Prevention

When it happens

Trigger: Passing a class whose basename is exactly 'Plugin' (strrchr finds '\', substr strips the last 6 chars 'Plugin' leaving empty string); e.g. a class named just \Some\Plugin that implements PluginInterface.

Common situations: An abstract base plugin class named 'Plugin' or a generically-named class accidentally passed to isFeaturePluginEnabled/enableFeaturePlugin/disableFeaturePlugin instead of the concrete plugin class.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/63e5cee758384f31. Report an issue: GitHub.

Appendix: source

Thrown at src/Utility/Application/FeaturePluginAwareTrait.php:67

    {
        Configure::write($this->getPluginEnabledConfigurationKey($name), false);
    }

    /**
     * @param string $name Plugin class name or plugin name, either upper case or lower case first (without the "Passbolt/" prefix)
     * @return string
     * @throws \Cake\Http\Exception\InternalErrorException if the plugin name is a class and not a plugin interface
     */
    protected function getPluginEnabledConfigurationKey(string $name): string
    {
        if (class_exists($name)) {
            if (!is_subclass_of($name, PluginInterface::class)) {
                throw new InternalErrorException("The class {$name} should implement PluginInterface::class.");
            }

            $extractedName = substr(substr(strrchr($name, '\\'), 1), 0, -6);
            if (empty($extractedName)) {
                throw new InternalErrorException("The class {$name} is not a valid plugin.");
            }

            $name = $extractedName;
        }

        $name = lcfirst($name);

        return "passbolt.plugins.{$name}.enabled";
    }
}

View on GitHub (pinned to 31c1bbc10f)