octobercms/october · error · SystemException
Handler does not exist
Error message
Handler does not exist
What it means
The second guard in VueReportWidgetBase::runHandler(): after the name passes the on* regex, method_exists($this, $handlerName) must find a public method on the widget class, otherwise SystemException('Handler does not exist') is thrown. This means the name is well-formed but the widget class defines no such method — the handler was renamed, lives on a different class, or the wrong widget class is handling the request.
Source
Thrown at modules/dashboard/classes/VueReportWidgetBase.php:73
$this->controller->registerVueComponent($this::class);
}
/**
* getData
*/
abstract public function getData(ReportFetchData $data): mixed;
/**
* runHandler
*/
public function runHandler(array $widgetConfig, string $handlerName, array $extraData): mixed
{
if (!preg_match('/^on[a-z0-9_]+/i', $handlerName)) {
throw new SystemException('Invalid handler name');
}
if (!method_exists($this, $handlerName)) {
throw new SystemException('Handler does not exist');
}
return $this->{$handlerName}($widgetConfig, $extraData);
}
}
View on GitHub (pinned to b608633a7e)
Solutions
- Add or restore the public method with the exact requested name on the widget class: public function onLoadData(array $widgetConfig, array $extraData): mixed.
- Update the JS/front-end call to the current method name, and bust cached front-end assets after deploys.
- Verify the request is routed to the widget class that actually defines the handler (check the widget alias/class in the AJAX payload).
- If the handler moved, keep a deprecated onOldName() wrapper delegating to the new one during transition.
Example fix
// before
// JS: this.requestHandler('onLoadData') but the class only has onRefreshData()
// after
public function onLoadData(array $widgetConfig, array $extraData): mixed
{
return $this->onRefreshData($widgetConfig, $extraData);
} Defensive patterns
Strategy: type-guard
Validate before calling
$handler = (string) $request->input('handler', '');
if (!preg_match('/^on[a-z0-9_]+$/i', $handler) || !method_exists($widget, $handler)) {
throw new ApplicationException("Unknown handler '{$handler}' for widget " . get_class($widget));
}
$widget->runHandler($config, $handler, $extra); Type guard
function widgetHasHandler(VueReportWidgetBase $widget, string $name): bool
{
return preg_match('/^on[a-z0-9_]+$/i', $name) === 1
&& method_exists($widget, $name);
} Try / catch
try {
$result = $widget->runHandler($config, $handler, $extra);
} catch (SystemException $e) {
if (str_contains($e->getMessage(), 'Handler does not exist')) {
return response()->json(['error' => 'Unknown handler'], 422);
}
throw $e;
} Prevention
- Update JS call sites whenever a handler is renamed; version-bust cached assets on deploy.
- Keep handler methods public and defined on the widget class that serves the request.
- During renames, keep a delegating onOldName() wrapper until front-ends catch up.
When it happens
Trigger: Front-end still calls 'onRefreshData' after the method was renamed to 'onLoadData'; the AJAX route resolves to a different VueReportWidget subclass than the one containing the handler (wrong widget alias/class in the request); method defined but on a trait not used by the class, or defined as private/protected in a scope method_exists still finds but invocation may fail — check visibility too.
Common situations: Renaming a handler in PHP without updating the JS call site; duplicating a widget and forgetting to port its handlers; plugin version skew between front-end assets (cached JS) and back-end code.
Related errors
- Invalid handler name
- The provided class is not a dashboard widget: {$className}
- Widget class [{$widgetClass}] not registered.
- Widget class [{$widgetClass}] not registered.
- Trying to get selected row without a popup reference.
AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21).
Data as JSON: /api/errors/ef63a4857856e71d.
Report an issue: GitHub.