octobercms/october · error · ValidationException

Invalid dropdown option array returned by `%s::%s`

Error message

Invalid dropdown option array returned by `%s::%s`

What it means

ValidationException thrown while parsing a snippet property's dropdown options in `Class::method` form: the referenced method was found and called, but it did not return an array. Snippet property definitions may delegate options to a static/class method, and the contract is a plain array of key => label; anything else (null, string, Eloquent Collection, object) is rejected.

Source

Thrown at modules/cms/classes/Snippet.php:277

        return array_values($properties);
    }

    /**
     * dropDownOptionsToArray
     */
    protected static function dropDownOptionsToArray($optionsString)
    {
        if (strpos($optionsString, '::') !== false) {
            $options = explode('::', $optionsString);
            if (
                count($options) === 2 &&
                class_exists($options[0]) &&
                method_exists($options[0], $options[1])
            ) {
                $result = $options[0]::{$options[1]}();
                if (!is_array($result)) {
                    throw new ValidationException(['snippetProperties' => sprintf(
                        'Invalid dropdown option array returned by `%s::%s`',
                        $options[0],
                        $options[1]
                    )]);
                }

                return $result;
            }
        }

        $options = explode('|', $optionsString);

        $result = [];
        foreach ($options as $index => $optionStr) {
            $parts = explode(':', $optionStr, 2);

            if (count($parts) > 1) {
                $key = trim($parts[0]);

View on GitHub (pinned to b608633a7e)

Solutions

  1. Make the options method return a plain array: append `->all()` (or `->toArray()`) to Collection results.
  2. Declare the return type `: array` on the method so PHP itself fails fast at the source.
  3. Never return null/empty on error — return an empty array [] and log the cause.

Example fix

// before
class Options {
    public static function getList() {
        return Status::pluck('label', 'code'); // Collection, not array
    }
}

// after
class Options {
    public static function getList(): array {
        return Status::pluck('label', 'code')->all();
    }
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Before registering the snippet property, verify the options provider returns an array
if (strpos($options, '::') === 0 || strpos($options, '::') !== false) {
    [$class, $method] = explode('::', $options, 2);
    if (method_exists($class, $method) && !is_array($class::$method())) {
        // fix the provider before the snippet definition ships
        throw new \InvalidArgumentException("{$class}::{$method} must return an array");
    }
}

Type guard

/** Guarantees the 'Class::method' options provider yields a plain array. */
function assertDropdownOptionsArray(string $class, string $method): array
{
    $result = $class::$method();
    if (!is_array($result)) {
        throw new \InvalidArgumentException("{$class}::{$method} must return array, got " . gettype($result));
    }
    return $result;
}

Try / catch

try {
    $options = Snippet::dropDownOptionsToArray($def['options']);
} catch (Winter\Storm\Exception\ValidationException $e) {
    // surfaced in the editor as snippetProperties errors — point devs at the provider method
    return back()->withErrors($e->getErrors());
}

Prevention

When it happens

Trigger: Registering a snippet property with `'options' => 'MyPlugin\Classes\Options::getList'` where getList() returns null on an error path, a Laravel Collection (e.g. `pluck()` without `->all()`), or a scalar.

Common situations: Plugin authors returning Eloquent results directly instead of arrays; the method throwing/short-circuiting to null when a table is empty or a dependency is missing; refactors changing the return type.

Related errors


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