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
- Set PDO exception mode in the adapter descriptor so failures carry the real driver message: options => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
- Log and inspect the exact SQL passed to query() — the exception carries no driver details by itself
- 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
- Always create adapters with options => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] so prepare failures throw PDOException with the real driver message
- Log the exact SQL string on failure — CannotPrepareStatement itself carries no SQL context
- Test dynamic SQL against the real server (or a compatible test container) before shipping query builders
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
- Matched parameter was not found in parameters list
- Invalid bind parameter (1)
- The 'dialectClass' '{className}' must implement Phalcon\Db\D
- Savepoints are not supported by this database adapter
- The table must contain at least one column
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/ce3455c233eb766b.
Report an issue: GitHub.