octobercms/october · error · ApplicationException

Dynamic Inspector control options cannot be loaded for the s

Error message

Dynamic Inspector control options cannot be loaded for the specified class.

What it means

onInspectableGetOptions only resolves dynamic options for classes whose hierarchy includes System\Traits\PropertyContainer, verified with class_uses_recursive(). Any other class — even one that exists and autoloads — is rejected, because the handler instantiates the class and calls property APIs that only that trait provides. This is a server-side contract check on the class named by inspectorClassName.

Source

Thrown at modules/backend/traits/InspectableContainer.php:35

     */
    public function onInspectableGetOptions()
    {
        // Disable asset broadcasting
        $this->flushAssets();

        $property = trim(post('inspectorProperty'));
        if (!$property) {
            throw new ApplicationException('The property name is not specified.');
        }

        $className = trim(post('inspectorClassName'));
        if (!$className || $className === 'undefined') {
            throw new ApplicationException('The inspectable class name is not specified.');
        }

        $traitFound = in_array(\System\Traits\PropertyContainer::class, class_uses_recursive($className));
        if (!$traitFound) {
            throw new ApplicationException('Dynamic Inspector control options cannot be loaded for the specified class.');
        }

        $obj = new $className(null);
        $obj->setProperties(post());

        // Nested properties have names like object.property.
        // Convert them to Object.Property.
        $propertyNameParts = explode('.', $property);
        $propertyMethodName = '';
        foreach ($propertyNameParts as $part) {
            $part = trim($part);

            if (!strlen($part)) {
                continue;
            }

            $propertyMethodName .= ucfirst($part);
        }

View on GitHub (pinned to b608633a7e)

Solutions

  1. Make the target class use System\Traits\PropertyContainer — directly, or by extending a base like Cms\Classes\ComponentBase that already includes it.
  2. Double-check the fully-qualified class name posted as inspectorClassName; a wrong-but-existing class fails exactly here.
  3. After moving or renaming classes, run composer dump-autoload and clear caches.

Example fix

// before
class StockReports
{
}

// after
class StockReports
{
    use \System\Traits\PropertyContainer;
}

// or extend a base that already provides the trait
class StockReports extends \Cms\Classes\ComponentBase
{
}
Defensive patterns

Strategy: validation

Validate before calling

// Before pointing an inspector at a class, verify the contract server-side
$usable = class_exists($className)
    && in_array(\System\Traits\PropertyContainer::class, class_uses_recursive($className), true);

if (!$usable) {
    // choose a class that uses PropertyContainer, e.g. a ComponentBase
}

Type guard

function isPropertyContainerClass(string $class): bool
{
    return class_exists($class)
        && in_array(\System\Traits\PropertyContainer::class, class_uses_recursive($class), true);
}

Prevention

When it happens

Trigger: POST with a valid inspectorProperty and an existing inspectorClassName whose class tree does not include System\Traits\PropertyContainer — for example a plain PHP helper class, a DTO, or a model.

Common situations: Pointing an inspector control's dynamic options at a helper/DTO instead of a component; plugin authors exposing a new inspectable class but forgetting the trait; upgrades that restructured base classes and dropped the trait from the hierarchy.

Related errors


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