phalcon/cphalcon · error · Phalcon\Db\Exceptions\InvalidIndexColumns

Index definition 'columns' key must be an array

Error message

Index definition 'columns' key must be an array

What it means

Phalcon\Db\Index::__construct() accepts either a plain column list or a definition array detected by the presence of a 'columns' key. In the definition form, 'columns' must itself be an array of column names; a scalar — most commonly a single string — throws InvalidIndexColumns.

Source

Thrown at phalcon/Db/Index.zep:140

    /**
     * Phalcon\Db\Index constructor.
     *
     * Accepts either the legacy positional form `(name, columns, type)` or a
     * definition-array form `(name, ["columns" => [...], "type" => "...",
     * "invisible" => true, ...])`. Detection is based on the presence of a
     * `columns` key in the second argument; when present, the third
     * positional `type` argument is ignored in favor of the definition.
     */
    public function __construct( string name,  array columnsOrDefinition, string type = "")
    {
        var definitionType, invisible, directions, where, concurrent;

        let this->name = name;

        if isset columnsOrDefinition["columns"] {
            if unlikely typeof columnsOrDefinition["columns"] != "array" {
                throw new InvalidIndexColumns();
            }

            let this->columns = columnsOrDefinition["columns"];

            if fetch definitionType, columnsOrDefinition["type"] {
                let this->type = (string) definitionType;
            }

            if fetch invisible, columnsOrDefinition["invisible"] {
                let this->invisible = (bool) invisible;
            }

            if fetch directions, columnsOrDefinition["directions"] {
                if unlikely typeof directions != "array" {
                    throw new InvalidIndexDirections();
                }

                let this->directions = directions;

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Wrap the value in an array: ['columns' => ['user_id']]
  2. Normalize before construction: $cols = is_array($cols) ? $cols : [$cols]
  3. Guard definition builders with is_array($definition['columns']) assertions

Example fix

// before
new Index('idx_user', ['columns' => 'user_id', 'type' => 'INDEX']);

// after
new Index('idx_user', ['columns' => ['user_id'], 'type' => 'INDEX']);
Defensive patterns

Strategy: type-guard

Validate before calling

if (isset($definition['columns']) && !is_array($definition['columns'])) {
    $definition['columns'] = (array) $definition['columns']; // or throw
}
$index = new \Phalcon\Db\Index('idx_user', $definition);

Type guard

function isValidIndexDefinition(array $def): bool
{
    if (!isset($def['columns'])) {
        return true; // positional column-list form
    }
    return is_array($def['columns']);
}

Try / catch

try {
    $index = new \Phalcon\Db\Index('idx_user', $definition);
} catch (\Phalcon\Db\Exceptions\InvalidIndexColumns $e) {
    throw new InvalidArgumentException('Index columns must be an array of names', 0, $e);
}

Prevention

When it happens

Trigger: new Index('idx_user', ['columns' => 'user_id', 'type' => 'INDEX']); definitions built from JSON/YAML where a one-element list collapsed to a scalar; ['columns' => implode(',', $cols)].

Common situations: Single-column indexes declared in config files; YAML loaders that inline single-item sequences as plain strings; migration definitions assembled from user input without normalization.

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/ec08e7048236b615. Report an issue: GitHub.