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]);
    }

    /**
     * onGetWidgetStaticContent

View on GitHub (pinned to b608633a7e)

Solutions

  1. Include widgetClass (fully qualified class name) inside the widget_config POST array.
  2. Reuse the widget configuration the dashboard already assigned to the widget rather than rebuilding it in JS.
  3. Ensure widget_config is sent as a proper nested form array (widget_config[widgetClass]=...) and not a serialized string.
  4. 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

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


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