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

Invalid WHERE clause conditions

Error message

Invalid WHERE clause conditions

What it means

In update(), $whereCondition must be a string (appended raw to the UPDATE SQL, unescaped) or an array (with optional 'conditions', 'bind', 'bindTypes' keys). Any other type throws InvalidWhereConditions. Note that Zephir's typeof check rejects objects with __toString() too — a Stringable object is not a 'string' at this level, so it must be cast first.

Source

Thrown at phalcon/Db/Adapter/AbstractAdapter.zep:1455

        let escapedTable = this->escapeIdentifier(tableName),
            setClause    = join(", ", placeholders);

        if whereCondition !== null {
            let updateSql = "UPDATE " . escapedTable . " SET " . setClause . " WHERE ";

            /**
             * String conditions are simply appended to the SQL
             */
            if typeof whereCondition == "string" {
                let updateSql .= whereCondition;
            } else {

                /**
                 * Array conditions may have bound params and bound types
                 */
                if unlikely typeof whereCondition != "array" {
                    throw new InvalidWhereConditions();
                }

                /**
                 * If an index 'conditions' is present it contains string where
                 * conditions that are appended to the UPDATE SQL
                 */
                if fetch conditions, whereCondition["conditions"] {
                    let updateSql .= conditions;
                }

                /**
                 * Bound parameters are arbitrary values that are passed
                 * separately
                 */
                if fetch whereBind, whereCondition["bind"] {
                    merge_append(updateValues, whereBind);
                }

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Pass the condition as a string: "id = 123" (remember: not escaped — bind when values are dynamic)
  2. Or use the array form for safe binding: ['conditions' => 'id = ?', 'bind' => [$id], 'bindTypes' => [Column::BIND_PARAM_INT]]
  3. Cast Stringable objects: $where = (string) $exprObject before passing

Example fix

// before
$db->update('users', $fields, $values, $someConditionObject);

// after
$db->update('users', $fields, $values, [
    'conditions' => 'id = ?',
    'bind'       => [$id],
    'bindTypes'  => [Column::BIND_PARAM_INT],
]);
Defensive patterns

Strategy: validation

Validate before calling

if ($whereCondition !== null && !is_string($whereCondition) && !is_array($whereCondition)) {
    $whereCondition = is_object($whereCondition) && method_exists($whereCondition, '__toString')
        ? (string) $whereCondition
        : throw new InvalidArgumentException('whereCondition must be string or array');
}
$connection->update($table, $fields, $values, $whereCondition);

Prevention

When it happens

Trigger: $db->update('users', $fields, $values, 123); passing an object such as a PDOStatement, an expression builder result, or a value object with __toString(); passing null is fine (default) but false/float/int throw.

Common situations: Passing a where clause built by another library (query builder object) directly; Stringable enums/value objects used as conditions; truthy scalar conditions coming from untyped request data.

Related errors


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