{"record":{"id":"44fd336c11731cd4","repo":"octobercms/october","slug":"custom-widget-class-widgetclass-is-not-set","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.php","lineNumber":612,"sourceCode":"        $widgetConfig = (array) post('widget_config');\n\n        $dataSource = $this->getRequestedDataSource($widgetConfig);\n\n        return $dataSource->runHandler($handlerName);\n    }\n\n    /**\n     * onRunCustomWidgetHandler handler\n     */\n    public function onRunCustomWidgetHandler()\n    {\n        $handlerName = post('handler');\n        $widgetConfig = post('widget_config');\n        $extraData = post('extra_data', []);\n\n        $widgetClass = $widgetConfig['widgetClass'];\n        if (!$widgetClass) {\n            throw new SystemException(\"Custom widget class [{$widgetClass}] is not set.\");\n        }\n\n        $widget = DashManager::instance()->getVueReportWidget($widgetClass, $this->controller);\n        if (!$widget) {\n            throw new SystemException(\"Widget class [{$widgetClass}] not registered.\");\n        }\n\n        $result = $widget->runHandler(\n            $widgetConfig,\n            $handlerName,\n            $extraData\n        );\n\n        return $result;\n    }\n\n    /**\n     * makeDataSource","sourceCodeStart":594,"sourceCodeEnd":630,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/dashboard/widgets/Dash.php#L594-L630","documentation":"Dash::onRunCustomWidgetHandler is the AJAX endpoint that runs a handler on a custom (Vue) dashboard widget. It reads widget_config from POST and immediately requires widget_config.widgetClass to be a non-empty value. If the request omits widgetClass, a SystemException is thrown before DashManager is consulted, so the widget is never resolved.","triggerScenarios":"POSTing to the dashboard's handler endpoint (handler + widget_config) with widget_config missing the widgetClass key or set to an empty string; a custom widget's JavaScript sending {widget_config: {}} ; a renamed widget property in JS not updated on the PHP side.","commonSituations":"Custom Vue report widget whose request payload was hand-built and forgot widgetClass; front-end/back-end version mismatch after upgrading the dashboard module (payload key renamed); third-party widget copied from an older example that used a different key name.","solutions":["Include the widget's fully qualified class name under widget_config.widgetClass in the AJAX payload.","Send the payload via the framework's data-request / request API so widget_config mirrors the definition the dashboard already has (reuse widget.widgetClass from the widget config object).","If the widget class is correct but still empty, inspect the POST body (network tab) for key casing or nesting errors.","Update the custom widget to extend VueReportWidgetBase so the standard payload builder includes widgetClass."],"exampleFix":"// before (JS payload)\ndata: { handler: 'onMyAction', widget_config: { alias: 'sales' } }\n\n// after\ndata: { handler: 'onMyAction', widget_config: { widgetClass: 'MyPlugin\\ReportWidgets\\SalesWidget', alias: 'sales' } }","handlingStrategy":"validation","validationCode":"$widgetConfig = (array) post('widget_config');\nif (empty($widgetConfig['widgetClass']) || !is_string($widgetConfig['widgetClass'])) {\n    throw new \\ValidationException(['widgetClass' => 'widgetClass is required']);\n}","typeGuard":null,"tryCatchPattern":"try {\n    $result = $dash->onRunCustomWidgetHandler();\n} catch (\\SystemException $e) {\n    // payload missing widgetClass: fix the caller, do not retry blindly\n    return response()->json(['error' => $e->getMessage()], 422);\n}","preventionTips":["Always build widget_config from the widget's own config object so widgetClass is included.","Add a required-field check in JS before firing the AJAX handler.","Log the exact POST payload when this fires to spot renamed keys quickly."],"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"}