cakephp/cakephp · error · InvalidArgumentException

` ` is not a valid hook name. Must be one of ` .

Error message

`%s` is not a valid hook name. Must be one of `%s.`

What it means

Cake\Core\BasePlugin::checkHook() validates the $hook argument against static::VALID_HOOKS and throws InvalidArgumentException for anything else. It backs the plugin enable/disable/isEnabled API, so only hooks the plugin class declares as valid (typically 'bootstrap', 'routes', 'console', 'middleware', etc.) may be queried or toggled.

Solutions

  1. Use a hook name present in the plugin's VALID_HOOKS constant (check the concrete plugin class)
  2. Reference the constant directly instead of a literal: `$plugin->enable(BasePluginClass::VALID_HOOKS[0])` or a named constant
  3. Verify spelling/singular form of the hook string
  4. If you control the plugin, add the new hook to static::$hooks/VALID_HOOKS if it should be supported

Example fix

// before
$plugin->isEnabled('events'); // not a valid hook
// after
$plugin->isEnabled('bootstrap'); // one of static::VALID_HOOKS
Defensive patterns

Strategy: validation

Validate before calling

if (!in_array($hook, SomePlugin::VALID_HOOKS, true)) {
    return false; // or throw/with a clear message listing valid hooks
}
$enabled = $plugin->isEnabled($hook);

Type guard

function isValidPluginHook(string $hook, string $pluginClass): bool {
    return defined($pluginClass . '::VALID_HOOKS')
        && in_array($hook, $pluginClass::VALID_HOOKS, true);
}

Try / catch

try {
    $plugin->enable($hook);
} catch (\InvalidArgumentException $e) {
    // log invalid hook name; fall back to a valid default
    $plugin->enable('bootstrap');
}

Prevention

When it happens

Trigger: `$plugin->enable('hooks')`, `->disable('bootstrapx')`, `->isEnabled('service')` with a hook name not listed in the plugin class's VALID_HOOKS constant; typos or pluralization mistakes in the hook string; passing a hook a plugin subclass removed from its VALID_HOOKS.

Common situations: Configuration code enabling/disabling plugin features at bootstrap with hand-typed hook names; copy-pasted code between plugin classes with differing VALID_HOOKS; upgrading a plugin that removed or renamed hooks.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of cakephp/cakephp@1128eba9b0 (2026-09-12). Data as JSON: /api/errors/d35d11cc58936180. Report an issue: GitHub.

Appendix: source

Thrown at src/Core/BasePlugin.php:257

     */
    public function isEnabled(string $hook): bool
    {
        $this->checkHook($hook);

        return $this->{"{$hook}Enabled"} === true;
    }

    /**
     * Check if a hook name is valid
     *
     * @param string $hook The hook name to check
     * @throws \InvalidArgumentException on invalid hooks
     * @return void
     */
    protected function checkHook(string $hook): void
    {
        if (!in_array($hook, static::VALID_HOOKS, true)) {
            throw new InvalidArgumentException(sprintf(
                '`%s` is not a valid hook name. Must be one of `%s.`',
                $hook,
                implode(', ', static::VALID_HOOKS),
            ));
        }
    }

    /**
     * @inheritDoc
     */
    public function routes(RouteBuilder $routes): void
    {
        $path = $this->getConfigPath() . 'routes.php';
        if (is_file($path)) {
            $return = require $path;
            if ($return instanceof Closure) {
                $return($routes);
            }

View on GitHub (pinned to 1128eba9b0)