octobercms/october · error · SystemException

Widget class [{$widgetClass}] not registered.

Error message

Widget class [{$widgetClass}] not registered.

What it means

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.

Source

Thrown at modules/dashboard/widgets/Dash.php:617

    }

    /**
     * onRunCustomWidgetHandler handler
     */
    public function onRunCustomWidgetHandler()
    {
        $handlerName = post('handler');
        $widgetConfig = post('widget_config');
        $extraData = post('extra_data', []);

        $widgetClass = $widgetConfig['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.");
        }

        $result = $widget->runHandler(
            $widgetConfig,
            $handlerName,
            $extraData
        );

        return $result;
    }

    /**
     * makeDataSource
     */
    protected function makeDataSource(string $dataSourceClass): ReportDataSourceBase
    {
        $dataSourceManager = DashManager::instance();
        $dataSource = $dataSourceManager->getDataSource($dataSourceClass);

View on GitHub (pinned to b608633a7e)

Solutions

  1. Register the widget in the owning plugin: public function registerReportWidgets() { return ['MyPlugin\ReportWidgets\Sales' => ['label' => 'Sales']]; }
  2. Make the widget class extend Dashboard\Classes\VueReportWidgetBase (not ReportWidgetBase) so DashManager::listVueReportWidgets includes it.
  3. Confirm the exact fully qualified class name in the payload matches the registered key (case-sensitive, no leading backslash mismatch).
  4. Ensure the plugin is enabled; clear cache and re-run composer dump-autoload if the class file exists but is not autoloadable.

Example fix

// before
class SalesWidget extends \Backend\Classes\ReportWidgetBase {}

// after
class SalesWidget extends \Dashboard\Classes\VueReportWidgetBase {}

// Plugin.php
public function registerReportWidgets()
{
    return ['MyPlugin\ReportWidgets\SalesWidget' => ['label' => 'Sales']];
}
Defensive patterns

Strategy: validation

Validate before calling

$manager = \Dashboard\Classes\DashManager::instance();
if (!in_array($widgetClass, $manager->listVueReportWidgetClasses(), true)) {
    throw new \ValidationException(['widgetClass' => "{$widgetClass} is not a registered Vue report widget"]);
}

Type guard

/** True when the class is registered AND extends VueReportWidgetBase. */
function isRegisteredVueWidget(string $class): bool
{
    return in_array($class, \Dashboard\Classes\DashManager::instance()
        ->listVueReportWidgetClasses(), true);
}

Try / catch

try {
    $widget = DashManager::instance()->getVueReportWidget($class, $this->controller);
} catch (\SystemException $e) {
    \Log::error('Vue widget lookup failed: '.$e->getMessage());
    return ajax()->force(['error' => $e->getMessage()]);
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21). Data as JSON: /api/errors/068761f0fcb4316c. Report an issue: GitHub.