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

Cannot prepare statement

Error message

Cannot prepare statement

What it means

queryStatement() — the private path behind query() — calls PDO::prepare() and throws CannotPrepareStatement if the result is not an object. When PDO runs with the default silent error mode (PDO::ERRMODE_SILENT), prepare() returns false on unpreparable SQL (syntax error, unknown column/driver limitation) instead of raising a PDOException, and this guard converts that false into an exception. With PDO::ERRMODE_EXCEPTION configured, PDO itself throws the more informative PDOException first, so seeing CannotPrepareStatement usually means error mode was silent.

Source

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

        let eventsManager = <ManagerInterface> this->eventsManager;
        if typeof eventsManager == "object" {
            eventsManager->fire("db:connectionLost", this);
        }

        this->connect();
    }

    /**
     * Prepares and executes a read statement, returning the live PDOStatement.
     */
    private function queryStatement(string sqlStatement, array params, array types) -> <\PDOStatement>
    {
        var statement;

        let statement = this->pdo->prepare(sqlStatement);
        if unlikely typeof statement != "object" {
            throw new CannotPrepareStatement();
        }

        return this->executePrepared(statement, params, types);
    }
}

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Set PDO exception mode in the adapter descriptor so failures carry the real driver message: options => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
  2. Log and inspect the exact SQL passed to query() — the exception carries no driver details by itself
  3. Fix the SQL: check quoting, placeholder style, table/column names; run the statement manually in a DB client to compare

Example fix

// before
$db = new Mysql(['host' => $h, 'username' => $u, 'password' => $p, 'dbname' => $d]);
$db->query('SELECT FROM users WHERE id = 1'); // CannotPrepareStatement, no detail

// after
$db = new Mysql([
    'host' => $h, 'username' => $u, 'password' => $p, 'dbname' => $d,
    'options' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
]);
$db->query('SELECT * FROM users WHERE id = 1'); // PDOException with real syntax error
Defensive patterns

Strategy: try-catch

Try / catch

use Phalcon\Db\Exceptions\CannotPrepareStatement;

try {
    $result = $connection->query($sql, $params, $types);
} catch (CannotPrepareStatement $e) {
    // error mode was silent: surface driver details from errorInfo()
    $info = $connection->getErrorInfo();
    throw new RuntimeException(sprintf(
        'Query failed (%s): %s -- SQL: %s',
        $info[0] ?? '?', $info[2] ?? $e->getMessage(), $sql
    ), 0, $e);
}

Prevention

When it happens

Trigger: $connection->query($malformedSql) with a syntax error while PDO::ATTR_ERRMODE is not ERRMODE_EXCEPTION; statements the driver cannot prepare in the configured emulation mode; placeholder syntax mistakes (e.g. mixing ? and :name: or stray colons) making the statement unpreparable.

Common situations: Adapters created without options['PDO::ATTR_ERRMODE'] = PDO::ERRMODE_EXCEPTION; dynamically assembled SQL with a missing closing quote or bad JOIN clause; switching PDO::ATTR_EMULATE_PREPARES off/on exposing statements the server refuses to prepare; the generic message forcing developers to find the SQL bug without a driver error text.

Related errors


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