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.

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.

Appendix: 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)