octobercms/october · error · SystemException
Custom widget class [{$widgetClass}] is not set.
Error message
Custom widget class [{$widgetClass}] is not set. What it means
HasWidgetData::onGetWidgetCustomData fetches data for a custom dashboard widget. It reads post('widget_config[widgetClass]') and requires a non-empty value before consulting DashManager. If the AJAX payload lacks widgetClass, this SystemException is thrown immediately - the widget lookup and getData never run.
Source
Thrown at modules/dashboard/widgets/dash/HasWidgetData.php:78
$result['prev_date_start'] = $fetchData->compareDateStart->toDateString();
$result['prev_date_end'] = $fetchData->compareDateEnd->toDateString();
}
return ajax()->force($result);
}
/**
* onGetWidgetCustomData
*/
public function onGetWidgetCustomData()
{
$fetchData = new ReportFetchData;
$fetchData->fillFromPost();
$widgetClass = post('widget_config[widgetClass]');
if (!$widgetClass) {
throw new SystemException("Custom widget class [{$widgetClass}] is not set.");
}
$widget = DashManager::instance()->getVueReportWidget(
$widgetClass,
$this->controller
);
if (!$widget) {
throw new SystemException("Widget class [{$widgetClass}] not registered.");
}
$data = $widget->getData($fetchData);
return ajax()->force(['data' => $data]);
}
/**
* onGetWidgetStaticContentView on GitHub (pinned to b608633a7e)
Solutions
- Include widgetClass (fully qualified class name) inside the widget_config POST array.
- Reuse the widget configuration the dashboard already assigned to the widget rather than rebuilding it in JS.
- Ensure widget_config is sent as a proper nested form array (widget_config[widgetClass]=...) and not a serialized string.
- Update to a payload shape matching the module version in use after upgrades.
Example fix
// before
$.request('onGetWidgetCustomData', { data: { widget_config: { alias: 'sales' } } });
// after
$.request('onGetWidgetCustomData', { data: { widget_config: { widgetClass: 'MyPlugin\ReportWidgets\SalesWidget', alias: 'sales' } } }); Defensive patterns
Strategy: validation
Validate before calling
$widgetClass = post('widget_config[widgetClass]');
if (!is_string($widgetClass) || $widgetClass === '') {
throw new \ValidationException(['widgetClass' => 'widgetClass is required']);
} Try / catch
try {
$data = $dash->onGetWidgetCustomData();
} catch (\SystemException $e) {
return response()->json(['error' => $e->getMessage()], 422);
} Prevention
- Clone the dashboard-provided widget config instead of hand-assembling it.
- Assert required payload keys in a shared request builder used by all custom widgets.
- Cover payload shape with a JS unit test so refactors cannot silently drop widgetClass.
When it happens
Trigger: Calling the widget-data AJAX endpoint with widget_config that omits widgetClass; front-end code building widget_config from a partial object (e.g. only alias/type); a Vue component passing widget_config as a JSON string so the nested key never arrives.
Common situations: Custom widget front-ends assembled manually instead of reusing the dashboard's config object; payload key renamed between module versions; integrations that fetch widget data server-to-server and forget the class key.
Related errors
- Custom widget class [{$widgetClass}] is not set.
- The property name is not specified.
- Trying to get selected row without a popup reference.
- Unknown widget report interval {$widgetInterval}
- The provided class is not a report widget:
AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21).
Data as JSON: /api/errors/c2a9ec4622ef7abb.
Report an issue: GitHub.