{"record":{"id":"068761f0fcb4316c","repo":"octobercms/october","slug":"widget-class-widgetclass-not-registered","errorCode":null,"errorMessage":"Widget class [{$widgetClass}] not registered.","messagePattern":"Widget class \\[(.+?)\\] not registered\\.","errorType":"exception","errorClass":"SystemException","httpStatus":null,"severity":"error","filePath":"modules/dashboard/widgets/Dash.php","lineNumber":617,"sourceCode":"    }\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\n     */\n    protected function makeDataSource(string $dataSourceClass): ReportDataSourceBase\n    {\n        $dataSourceManager = DashManager::instance();\n        $dataSource = $dataSourceManager->getDataSource($dataSourceClass);","sourceCodeStart":599,"sourceCodeEnd":635,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/dashboard/widgets/Dash.php#L599-L635","documentation":"After a widgetClass is provided to Dash::onRunCustomWidgetHandler, DashManager::getVueReportWidget looks it up in the registered Vue report widget list. That list only contains report widgets registered through the plugin system that are subclasses of Dashboard\\Classes\\VueReportWidgetBase. An unknown class returns null and this SystemException is thrown.","triggerScenarios":"POSTing a handler request with widgetClass set to a class that is not registered via the plugin's registerReportWidgets(); registering the widget but extending Backend\\Classes\\ReportWidgetBase (or ReportWidgetBase) instead of VueReportWidgetBase, which excludes it from the Vue list; plugin providing the widget is disabled; fully qualified class name typo (wrong namespace/case).","commonSituations":"Building a first custom dashboard widget and forgetting the registration array in Plugin.php; widget works as a CMS report widget but is called through the Vue report path; class moved to another namespace during a refactor; plugin folder renamed so the class name no longer matches.","solutions":["Register the widget in the owning plugin: public function registerReportWidgets() { return ['MyPlugin\\ReportWidgets\\Sales' => ['label' => 'Sales']]; }","Make the widget class extend Dashboard\\Classes\\VueReportWidgetBase (not ReportWidgetBase) so DashManager::listVueReportWidgets includes it.","Confirm the exact fully qualified class name in the payload matches the registered key (case-sensitive, no leading backslash mismatch).","Ensure the plugin is enabled; clear cache and re-run composer dump-autoload if the class file exists but is not autoloadable."],"exampleFix":"// before\nclass SalesWidget extends \\Backend\\Classes\\ReportWidgetBase {}\n\n// after\nclass SalesWidget extends \\Dashboard\\Classes\\VueReportWidgetBase {}\n\n// Plugin.php\npublic function registerReportWidgets()\n{\n    return ['MyPlugin\\ReportWidgets\\SalesWidget' => ['label' => 'Sales']];\n}","handlingStrategy":"validation","validationCode":"$manager = \\Dashboard\\Classes\\DashManager::instance();\nif (!in_array($widgetClass, $manager->listVueReportWidgetClasses(), true)) {\n    throw new \\ValidationException(['widgetClass' => \"{$widgetClass} is not a registered Vue report widget\"]);\n}","typeGuard":"/** True when the class is registered AND extends VueReportWidgetBase. */\nfunction isRegisteredVueWidget(string $class): bool\n{\n    return in_array($class, \\Dashboard\\Classes\\DashManager::instance()\n        ->listVueReportWidgetClasses(), true);\n}","tryCatchPattern":"try {\n    $widget = DashManager::instance()->getVueReportWidget($class, $this->controller);\n} catch (\\SystemException $e) {\n    \\Log::error('Vue widget lookup failed: '.$e->getMessage());\n    return ajax()->force(['error' => $e->getMessage()]);\n}","preventionTips":["Register every custom dashboard widget in registerReportWidgets() as part of the plugin checklist.","Extend VueReportWidgetBase for dashboard widgets; keep ReportWidgetBase for form/widget contexts.","Add a boot-time sanity assertion in dev envs that every widget referenced in default dashboards is registered."],"tags":["dashboard","widget-registration","vue-report-widget","plugin"],"backgroundTag":"widget-not-registered","analyzedSha":"b608633a7e8922487d91a8161499020121c3b3bf","analyzedAt":"2026-08-21T04:24:57.515Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}