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

Invalid bind parameter (1)

Error message

Invalid bind parameter (1)

What it means

executePrepared(statement, placeholders, dataTypes) iterates the placeholders array by key; integer keys are treated as positional parameters (key + 1) and string keys as named parameters. Any key of another type throws InvalidBindParameter ('Invalid bind parameter (1)'). In pure PHP, array keys are always int or string, so this surfaces through non-userland placeholders — e.g. structures produced by json_decode() with unexpected keys, generators collapsed wrongly, or direct calls from other extension/Zephir code.

Source

Thrown at phalcon/Db/Adapter/Pdo/AbstractPdo.zep:514

     *         "inv_title" => "Test Invoice",
     *     ],
     *     [
     *         "inv_title" => Column::BIND_PARAM_STR,
     *     ]
     * );
     *```
     */
    public function executePrepared(<\PDOStatement> statement,  array placeholders, array dataTypes = []) -> <\PDOStatement>
    {
        var wildcard, value, type, castValue, parameter, position, itemValue;

        for wildcard, value in placeholders {
            if typeof wildcard == "integer" {
                let parameter = wildcard + 1;
            } elseif typeof wildcard == "string" {
                let parameter = wildcard;
            } else {
                throw new InvalidBindParameter();
            }

            if fetch type, dataTypes[wildcard] {
                /**
                 * The bind type needs to be string because the precision
                 * is lost if it is casted as a double
                 */
                if type == Column::BIND_PARAM_DECIMAL {
                    let castValue = (string) value,
                        type = Column::BIND_SKIP;
                } else {
                    if Settings::get("db.force_casting") {
                        if typeof value != "array" {
                            switch type {

                                case Column::BIND_PARAM_INT:
                                    let castValue = intval(value, 10);
                                    break;

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Pass placeholders as a positional list [value, value, ...] built with array_values(), or an assoc [name => value] map with string keys
  2. Normalize any incoming bind structure before calling: cast keys, re-index lists
  3. Prefer the public query()/execute() APIs which run the same pipeline with validated input

Example fix

// before
$stmt = $connection->prepare('SELECT * FROM users WHERE id = ?');
$connection->executePrepared($stmt, $maybeMalformedBindArray, []);

// after
$stmt = $connection->prepare('SELECT * FROM users WHERE id = ?');
$connection->executePrepared($stmt, array_values($maybeMalformedBindArray), []);
Defensive patterns

Strategy: type-guard

Type guard

/** Ensure every placeholder key is int (positional) or string (named). */
function normalizeBindKeys(array $placeholders): array
{
    $out = [];
    foreach ($placeholders as $k => $v) {
        if (is_int($k) || is_string($k)) {
            $out[$k] = $v;
        } else {
            throw new InvalidArgumentException('Invalid bind key type: ' . gettype($k));
        }
    }
    return $out;
}

$connection->executePrepared($stmt, normalizeBindKeys($placeholders), $dataTypes);

Prevention

When it happens

Trigger: Calling executePrepared() directly (it is public) with a malformed placeholders array whose keys are not plain integers or strings; passing a data structure where values ended up as keys or where key normalization (floats, nulls) happened upstream.

Common situations: Custom query layers that build bind arrays from decoded JSON or object casts; integrating with libraries that hand over untyped maps; rare direct use of this low-level method instead of query()/execute().

Related errors


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