octobercms/october · error · SystemException

Checkbox and radiobutton dropdown menu items cannot have ico

Error message

Checkbox and radiobutton dropdown menu items cannot have icons

What it means

ItemDefinition::setIcon() rejects icons on checkbox and radiobutton items: those types render a checked/unchecked state glyph instead of an icon, and the menu layout has no slot for both. The PHP-side guard fails fast so an invalid menu never reaches the browser — the frontend enforces the mirror rule at render time (see the dropdownmenu sheet check).

Source

Thrown at modules/backend/vuecomponents/dropdownmenu/ItemDefinition.php:141

    }

    /**
     * setDisabled
     */
    public function setDisabled(bool $value)
    {
        $this->disabled = $value;

        return $this;
    }

    /**
     * setIcon
     */
    public function setIcon(string $value)
    {
        if (in_array($this->type, [self::TYPE_CHECKBOX, self::TYPE_RADIOBUTTON])) {
            throw new SystemException('Checkbox and radiobutton dropdown menu items cannot have icons');
        }

        $this->icon = $value;

        return $this;
    }

    /**
     * setChecked
     */
    public function setChecked(bool $value)
    {
        $this->checked = $value;
    }

    /**
     * addItem
     */

View on GitHub (pinned to b608633a7e)

Solutions

  1. Only call setIcon() for non-stateful types (link, button, submenu).
  2. If the icon matters more than the check state, keep the item a plain type instead of checkbox/radiobutton.
  3. Filter icons out when building checkbox/radio items from shared configuration.

Example fix

// before
$item = (new ItemDefinition(ItemDefinition::TYPE_CHECKBOX, 'Enabled', 'toggle'))
    ->setIcon('icon-check');

// after - stateful items render their own glyph
$item = new ItemDefinition(ItemDefinition::TYPE_CHECKBOX, 'Enabled', 'toggle');

// or keep the icon by using a plain item
$item = (new ItemDefinition(ItemDefinition::TYPE_BUTTON, 'Enabled', 'toggle'))
    ->setIcon('icon-check');
Defensive patterns

Strategy: type-guard

Type guard

function itemCanHaveIcon($item): bool
{
    return !in_array(
        $item->type,
        [ItemDefinition::TYPE_CHECKBOX, ItemDefinition::TYPE_RADIOBUTTON],
        true
    );
}

// usage in a menu builder
if ($icon && itemCanHaveIcon($item)) {
    $item->setIcon($icon);
}

Prevention

When it happens

Trigger: Calling setIcon('icon-copy') on an item created as ItemDefinition::TYPE_CHECKBOX or ItemDefinition::TYPE_RADIOBUTTON; menu-builder loops that call setIcon on every item regardless of type.

Common situations: A generic item factory applying icons from config to all items including stateful ones; converting a normal menu item to a checkbox item and forgetting to drop the icon.

Related errors


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