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

Index definition 'where' key must be a string

Error message

Index definition 'where' key must be a string

What it means

In the definition-array form of Index::__construct(), an optional partial-index 'where' key must be a string containing the raw SQL predicate. Any non-string value (array, int, bool) throws InvalidIndexWhere.

Source

Thrown at phalcon/Db/Index.zep:163

            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;
            }

            if fetch where, columnsOrDefinition["where"] {
                if unlikely typeof where != "string" {
                    throw new InvalidIndexWhere();
                }

                let this->where = where;
            }

            if fetch concurrent, columnsOrDefinition["concurrently"] {
                let this->concurrent = (bool) concurrent;
            }
        } else {
            let this->columns = columnsOrDefinition;
            let this->type    = type;
        }
    }

    /**
     * Index columns
     */
    public function getColumns() -> array

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Pass the predicate as raw SQL: 'where' => 'active = 1'
  2. Build the string deliberately (e.g. implode(' AND ', $conditions)) instead of passing an array
  3. Validate with is_string($definition['where']) before constructing Index

Example fix

// before
new Index('idx_active', ['columns' => ['active'], 'where' => ['active' => 1]]);

// after
new Index('idx_active', ['columns' => ['active'], 'where' => 'active = 1']);
Defensive patterns

Strategy: type-guard

Validate before calling

if (isset($definition['where']) && !is_string($definition['where'])) {
    throw new InvalidArgumentException("Index 'where' must be a raw SQL predicate string, e.g. 'active = 1'");
}
$index = new \Phalcon\Db\Index('idx_active', $definition);

Type guard

function isValidIndexDefinition(array $def): bool
{
    return !isset($def['columns'])
        || (is_array($def['columns'])
            && (!isset($def['where']) || is_string($def['where'])));
}

Try / catch

try {
    $index = new \Phalcon\Db\Index('idx_active', $definition);
} catch (\Phalcon\Db\Exceptions\InvalidIndexWhere $e) {
    throw new InvalidArgumentException("Partial-index 'where' must be SQL text, not an array", 0, $e);
}

Prevention

When it happens

Trigger: ['columns' => ['active'], 'where' => ['active' => 1]] passing a conditions array instead of SQL text; 'where' => true or an integer flag; query-builder output that is still an array when handed to Index.

Common situations: Developers expressing the predicate as a field=>value map (common in ORM find() styles); config flags accidentally placed under 'where'; partial-index definitions ported from other tools.

Related errors


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