{"record":{"id":"c2a9ec4622ef7abb","repo":"octobercms/october","slug":"custom-widget-class-widgetclass-is-not-set-c2a9ec","errorCode":null,"errorMessage":"Custom widget class [{$widgetClass}] is not set.","messagePattern":"Custom widget class \\[(.+?)\\] is not set\\.","errorType":"exception","errorClass":"SystemException","httpStatus":null,"severity":"error","filePath":"modules/dashboard/widgets/dash/HasWidgetData.php","lineNumber":78,"sourceCode":"\n            $result['prev_date_start'] = $fetchData->compareDateStart->toDateString();\n            $result['prev_date_end'] = $fetchData->compareDateEnd->toDateString();\n        }\n\n        return ajax()->force($result);\n    }\n\n    /**\n     * onGetWidgetCustomData\n     */\n    public function onGetWidgetCustomData()\n    {\n        $fetchData = new ReportFetchData;\n        $fetchData->fillFromPost();\n\n        $widgetClass = post('widget_config[widgetClass]');\n        if (!$widgetClass) {\n            throw new SystemException(\"Custom widget class [{$widgetClass}] is not set.\");\n        }\n\n        $widget = DashManager::instance()->getVueReportWidget(\n            $widgetClass,\n            $this->controller\n        );\n\n        if (!$widget) {\n            throw new SystemException(\"Widget class [{$widgetClass}] not registered.\");\n        }\n\n        $data = $widget->getData($fetchData);\n\n        return ajax()->force(['data' => $data]);\n    }\n\n    /**\n     * onGetWidgetStaticContent","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/dashboard/widgets/dash/HasWidgetData.php#L60-L96","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n$.request('onGetWidgetCustomData', { data: { widget_config: { alias: 'sales' } } });\n\n// after\n$.request('onGetWidgetCustomData', { data: { widget_config: { widgetClass: 'MyPlugin\\ReportWidgets\\SalesWidget', alias: 'sales' } } });","handlingStrategy":"validation","validationCode":"$widgetClass = post('widget_config[widgetClass]');\nif (!is_string($widgetClass) || $widgetClass === '') {\n    throw new \\ValidationException(['widgetClass' => 'widgetClass is required']);\n}","typeGuard":null,"tryCatchPattern":"try {\n    $data = $dash->onGetWidgetCustomData();\n} catch (\\SystemException $e) {\n    return response()->json(['error' => $e->getMessage()], 422);\n}","preventionTips":["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."],"tags":["dashboard","ajax","request-payload","widget"],"backgroundTag":"missing-request-parameter","analyzedSha":"b608633a7e8922487d91a8161499020121c3b3bf","analyzedAt":"2026-08-21T04:24:57.515Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}