octobercms/october · error · SystemException

A widget class name ':name' has not been registered

Error message

A widget class name ':name' has not been registered

What it means

WidgetMaker::makeWidget() instantiates a backend widget class by name and throws this localized error (backend::lang.widget.not_registered) when class_exists($class) fails. Despite the wording, nothing needs runtime 'registration' — the fully-qualified class name simply must be autoloadable. Controllers use this to build Search, Toolbar and Filter widgets, so a bad name breaks the whole controller view.

Source

Thrown at modules/backend/traits/WidgetMaker.php:43

            : $this;

        return $controller->widget->{$name} ?? null;
    }

    /**
     * makeWidget object with the supplied configuration file.
     * @param string $class
     * @param array $widgetConfig
     * @return \Backend\Classes\WidgetBase
     */
    public function makeWidget($class, $widgetConfig = [])
    {
        $controller = property_exists($this, 'controller') && $this->controller
            ? $this->controller
            : $this;

        if (!class_exists($class)) {
            throw new SystemException(Lang::get('backend::lang.widget.not_registered', [
                'name' => $class
            ]));
        }

        return new $class($controller, $widgetConfig);
    }

    /**
     * makeFormWidget object with the supplied form field and widget configuration.
     * The fieldConfig is a field name, an array of config or a FormField object.
     * @param string $class
     * @param mixed $fieldConfig
     * @param array $widgetConfig
     * @return \Backend\Classes\FormWidgetBase
     */
    public function makeFormWidget($class, $fieldConfig = [], $widgetConfig = [])
    {
        $controller = property_exists($this, 'controller') && $this->controller

View on GitHub (pinned to b608633a7e)

Solutions

  1. Use the ::class constant of an imported class instead of a hand-typed string: $this->makeWidget(\Backend\Widgets\Search::class).
  2. Compare the exact string from the error message against the real class name for typos, case, and namespace segments.
  3. Ensure the defining plugin is installed and run composer dump-autoload.
  4. If the name comes from config, validate it against known widget classes before calling makeWidget().

Example fix

// before
$widget = $this->makeWidget('Backend\\Widgets\\Seach');

// after
use Backend\Widgets\Search;

$widget = $this->makeWidget(Search::class);
Defensive patterns

Strategy: validation

Validate before calling

$widgetClass = $config['widget'] ?? null;
if (!$widgetClass || !class_exists($widgetClass)) {
    throw new InvalidArgumentException('Unknown widget class: ' . var_export($widgetClass, true));
}
$widget = $this->makeWidget($widgetClass);

Type guard

function isBackendWidgetClass(string $class): bool
{
    return class_exists($class) && is_a($class, \Backend\Classes\WidgetBase::class, true);
}

Try / catch

try {
    $widget = $this->makeWidget($class);
} catch (SystemException $e) {
    // class_exists failed - the config referenced an unloadable widget
    Log::error('makeWidget failed', ['class' => $class, 'error' => $e->getMessage()]);
    abort(404, 'This page is misconfigured.');
}

Prevention

When it happens

Trigger: $this->makeWidget('Backend\Widgets\Seach') (typo); $this->makeWidget($config->widget) where the config supplies an empty, aliased, or misspelled name; a plugin widget namespace that does not match the file path.

Common situations: Widget class strings coming from YAML/PHP config files with typos or wrong case; missing `use` imports so short names resolve incorrectly; a plugin that failed to boot so its classes never load; stale composer autoload after plugin changes.

Related errors


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