octobercms/october · error · ApplicationException

The inspectable class name is not specified.

Error message

The inspectable class name is not specified.

What it means

The same onInspectableGetOptions handler rejects the request when the inspectorClassName POST field is missing, empty after trim(), or the literal string 'undefined'. That field tells the server which class (usually a component using PropertyContainer) computes the options; the inspector frontend fills it from the control's serverClassName (see control-base.js loadDynamicOptions). The 'undefined' special case exists because an unset JS variable serializes to the string 'undefined' in form data.

Source

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

 */
trait InspectableContainer
{
    /**
     * onInspectableGetOptions
     */
    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)) {

View on GitHub (pinned to b608633a7e)

Solutions

  1. Set the server class name on the inspector control/host, e.g. this.serverClassName = 'MyPlugin\\Components\\MyComponent' in a custom control, or fix the configured inspectorClassName of the host.
  2. Verify the value is a fully-qualified, non-empty class name string — not a leaked JS undefined.
  3. If invoking the handler from tests or custom JS, always include inspectorClassName in the POST data.

Example fix

// before (custom control never sets serverClassName)
loadDynamicOptions() { /* serverClassName is undefined */ }

// after
this.serverClassName = 'MyPlugin\\Components\\MyComponent';
Defensive patterns

Strategy: validation

Validate before calling

// Before sending the dynamic-options request
const className = this.serverClassName;
if (typeof className !== 'string' || !className.trim() || className === 'undefined') {
    console.error('serverClassName is not set on the inspector control');
    return;
}
const payload = {
    inspectorProperty: control.property,
    inspectorClassName: className
};

Type guard

function hasServerClassName(control) {
    return typeof control.serverClassName === 'string'
        && control.serverClassName.trim().length > 0
        && control.serverClassName !== 'undefined';
}

Prevention

When it happens

Trigger: POST to onInspectableGetOptions where inspectorClassName is absent, empty, or exactly 'undefined' — typically because this.serverClassName was never set on the inspector control/host, or the JS variable holding the class name was undefined and got stringified into the payload.

Common situations: A custom inspector control that forgets to set serverClassName; refactors that moved or renamed the inspectable class without updating the frontend reference; hand-built requests from tests that omit the field.

Related errors


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