{"record":{"id":"bd475ca2d217326e","repo":"octobercms/october","slug":"cms-lang-ajax-handler-invalid-name","errorCode":null,"errorMessage":"cms::lang.ajax_handler.invalid_name","messagePattern":"cms::lang\\.ajax_handler\\.invalid_name","errorType":"exception","errorClass":"CmsException","httpStatus":null,"severity":"error","filePath":"modules/cms/classes/controller/HasAjaxRequests.php","lineNumber":125,"sourceCode":"\n        return [];\n    }\n\n    /**\n     * execAjaxHandlers executes the page, layout, component and plugin AJAX handlers.\n     * @return mixed Returns the AJAX Response object or null.\n     */\n    protected function execAjaxHandlers()\n    {\n        $handler = $this->getAjaxHandler();\n        if (!$handler) {\n            return null;\n        }\n\n        try {\n            // Validate the handler name\n            if (!preg_match('/^(?:\\w+\\:{2})?on[A-Z]{1}[\\w+]*$/', $handler)) {\n                throw new CmsException(Lang::get('cms::lang.ajax_handler.invalid_name', ['name'=>e($handler)]));\n            }\n\n            // Validates the handler partial list\n            $partialList = $this->getAjaxHandlerPartialList();\n\n            // Execute the handler\n            $result = null;\n            if ($this->partialWatcher) {\n                if ($exception = $this->partialWatcher->getHandlerException()) {\n                    throw $exception;\n                }\n\n                $result = $this->partialWatcher->getHandlerResponse();\n            }\n\n            if (!$result) {\n                $result = $this->runAjaxHandler($handler);\n            }","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/cms/classes/controller/HasAjaxRequests.php#L107-L143","documentation":"Before an AJAX handler executes, its name is checked against the pattern ^(?:\\w+\\:{2})?on[A-Z]{1}[\\w+]*$: optionally a component alias plus '::', then 'on' followed by an uppercase letter (camelCase). Names like 'onsave', 'on_save', 'save' or 'alias::on1go' fail the check and throw this CmsException immediately, before any handler lookup.","triggerScenarios":"data-request (or the handler field of a manual AJAX request) set to a handler that does not follow the camelCase onX convention: 'onsave', 'on_save', 'delete', 'Alias::onsave', 'on1thing', or a name with invalid characters.","commonSituations":"PHP handler renamed without updating the markup attribute; snake_case conventions carried over from other frameworks; copy-pasting a REST-style endpoint name ('save', 'submit') into data-request.","solutions":["Rename the handler to camelCase onX form: onsave -> onSave, on_save -> onSave, keeping both the markup attribute and the PHP method in sync","When targeting a component, write 'componentAlias::onHandler' with the alias exactly as defined in the page","Check for stray whitespace or encoded characters in the data-request value"],"exampleFix":"<!-- before -->\n<button data-request=\"on_save\">Save</button>\n==\nfunction on_save() { }\n\n<!-- after -->\n<button data-request=\"onSave\">Save</button>\n==\nfunction onSave() { }","handlingStrategy":"validation","validationCode":"if (!preg_match('/^(?:\\w+\\:{2})?on[A-Z]{1}[\\w+]*$/', $handler)) {\n    // reject or auto-correct (e.g. 'on_save' -> 'onSave') before issuing the request\n    return false;\n}","typeGuard":"function isValidHandlerName(h) {\n  return /^(?:\\w+::)?on[A-Z]\\w*$/.test(h);\n}","tryCatchPattern":null,"preventionTips":["Adopt a strict camelCase onX convention for handlers in code review","Centralize handler names in constants or data attributes instead of typing them per-button","Test AJAX wiring on every page that uses it after renames"],"tags":["ajax","handler","validation","cms","winter-cms"],"backgroundTag":"invalid-handler-name","analyzedSha":"b608633a7e8922487d91a8161499020121c3b3bf","analyzedAt":"2026-08-21T04:24:57.515Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}