{"record":{"id":"d35d11cc58936180","repo":"cakephp/cakephp","slug":"s-is-not-a-valid-hook-name-must-be-one-of-s","errorCode":null,"errorMessage":"`%s` is not a valid hook name. Must be one of `%s.`","messagePattern":"`(.+?)` is not a valid hook name\\. Must be one of `(.+?)\\.`","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Core/BasePlugin.php","lineNumber":257,"sourceCode":"     */\n    public function isEnabled(string $hook): bool\n    {\n        $this->checkHook($hook);\n\n        return $this->{\"{$hook}Enabled\"} === true;\n    }\n\n    /**\n     * Check if a hook name is valid\n     *\n     * @param string $hook The hook name to check\n     * @throws \\InvalidArgumentException on invalid hooks\n     * @return void\n     */\n    protected function checkHook(string $hook): void\n    {\n        if (!in_array($hook, static::VALID_HOOKS, true)) {\n            throw new InvalidArgumentException(sprintf(\n                '`%s` is not a valid hook name. Must be one of `%s.`',\n                $hook,\n                implode(', ', static::VALID_HOOKS),\n            ));\n        }\n    }\n\n    /**\n     * @inheritDoc\n     */\n    public function routes(RouteBuilder $routes): void\n    {\n        $path = $this->getConfigPath() . 'routes.php';\n        if (is_file($path)) {\n            $return = require $path;\n            if ($return instanceof Closure) {\n                $return($routes);\n            }","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/cakephp/cakephp/blob/1128eba9b09f1946df684811350e26f2cef68fac/src/Core/BasePlugin.php#L239-L275","documentation":"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.","triggerScenarios":"`$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.","commonSituations":"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.","solutions":["Use a hook name present in the plugin's VALID_HOOKS constant (check the concrete plugin class)","Reference the constant directly instead of a literal: `$plugin->enable(BasePluginClass::VALID_HOOKS[0])` or a named constant","Verify spelling/singular form of the hook string","If you control the plugin, add the new hook to static::$hooks/VALID_HOOKS if it should be supported"],"exampleFix":"// before\n$plugin->isEnabled('events'); // not a valid hook\n// after\n$plugin->isEnabled('bootstrap'); // one of static::VALID_HOOKS","handlingStrategy":"validation","validationCode":"if (!in_array($hook, SomePlugin::VALID_HOOKS, true)) {\n    return false; // or throw/with a clear message listing valid hooks\n}\n$enabled = $plugin->isEnabled($hook);","typeGuard":"function isValidPluginHook(string $hook, string $pluginClass): bool {\n    return defined($pluginClass . '::VALID_HOOKS')\n        && in_array($hook, $pluginClass::VALID_HOOKS, true);\n}","tryCatchPattern":"try {\n    $plugin->enable($hook);\n} catch (\\InvalidArgumentException $e) {\n    // log invalid hook name; fall back to a valid default\n    $plugin->enable('bootstrap');\n}","preventionTips":["Always source hook names from the plugin's VALID_HOOKS constant, not string literals","Centralize hook names in app-level constants","Check plugin docs/changelog when upgrading for removed hooks","Unit-test plugin bootstrap configuration"],"tags":["cakephp","plugins","hooks","invalid-argument"],"backgroundTag":"invalid-enum-value","analyzedSha":"1128eba9b09f1946df684811350e26f2cef68fac","analyzedAt":"2026-09-12T12:07:00.388Z","contentChangedAt":"2026-09-12T12:07:00.388Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}