phalcon/cphalcon · error · Phalcon\Db\Exceptions\MatchedParameterNotFound
Matched parameter was not found in parameters list
Error message
Matched parameter was not found in parameters list
What it means
convertBoundParams(sql, params) scans SQL for placeholders using BIND_PATTERN '/\?([0-9]+)|:([a-zA-Z0-9_]+):/' — positional ?N and named :name: with a trailing colon — and looks each capture up in params. This variant is the branch where the first lookup fails and there is no alternate name group to try: the placeholder in the SQL has no matching key in params. The SQL and the params array are out of sync.
Source
Thrown at phalcon/Db/Adapter/Pdo/AbstractPdo.zep:366
* )
* );
*```
*/
public function convertBoundParams( string sql, array params = []) -> array
{
var boundSql, placeHolders, bindPattern, matches, setOrder, placeMatch,
value;
let placeHolders = [],
bindPattern = self::BIND_PATTERN,
matches = null,
setOrder = 2;
if preg_match_all(bindPattern, sql, matches, setOrder) {
for placeMatch in matches {
if !fetch value, params[placeMatch[1]] {
if unlikely !isset placeMatch[2] {
throw new MatchedParameterNotFound();
}
if unlikely !fetch value, params[placeMatch[2]] {
throw new MatchedParameterNotFound();
}
}
let placeHolders[] = value;
}
let boundSql = preg_replace(bindPattern, "?", sql);
} else {
let boundSql = sql;
}
return [
"sql" : boundSql,
"params" : placeHoldersView on GitHub (pinned to b7419de9cd)
Solutions
- Keep SQL placeholders and params keys exactly in sync: every :name: needs params['name'], every ?N needs params[N]
- For Postgres ::type casts adjacent to another colon, rewrite as CAST(expr AS type) so the pattern does not match
- Rebuild params from the same source that builds the SQL instead of maintaining two artifacts
Example fix
// before $sql = 'SELECT * FROM users WHERE city = :city:'; $params = ['town' => 'Berlin']; $result = $connection->convertBoundParams($sql, $params); // after $sql = 'SELECT * FROM users WHERE city = :city:'; $params = ['city' => 'Berlin']; $result = $connection->convertBoundParams($sql, $params);
Defensive patterns
Strategy: validation
Validate before calling
// mirror of the internal BIND_PATTERN '/\?([0-9]+)|:([a-zA-Z0-9_]+):/'
preg_match_all('/\?([0-9]+)|:([a-zA-Z0-9_]+):/', $sql, $m, PREG_SET_ORDER);
foreach ($m as $match) {
$key = $match[1] !== '' ? (int) $match[1] : $match[2];
if (!array_key_exists($key, $params)) {
throw new InvalidArgumentException("SQL placeholder '{$key}' missing from params");
}
}
$connection->convertBoundParams($sql, $params); Try / catch
use Phalcon\Db\Exceptions\MatchedParameterNotFound;
try {
[$sql, $values] = $connection->convertBoundParams($sql, $params);
} catch (MatchedParameterNotFound $e) {
throw new RuntimeException('SQL/params mismatch: ' . $e->getMessage() . ' in: ' . $sql, 0, $e);
} Prevention
- Build SQL and params in the same conditional branch so a placeholder is never added without its param
- Remember ?N maps to params[N] directly — re-indexing params with array_values shifts meaning
- Escape or rewrite literal colon-wrapped text in SQL (Postgres ::casts, timestamps) to avoid phantom placeholder matches
When it happens
Trigger: SQL contains ?2 but params only has indexes 0/1 (note: ?2 maps to params[2] directly, not the second positional param); SQL contains :city: but params is ['town' => ...] after a rename; params keys renamed or dropped while the SQL string was left unchanged.
Common situations: Renaming bind variable names in raw SQL but not the params array; positional placeholders where the params array was re-indexed (array_values, array_merge, sort) breaking expected indexes; literal text in SQL accidentally matching the pattern — e.g. Postgres double casts like value::numeric::text contain ':numeric:' which is treated as a placeholder.
Related errors
- Incomplete number of bind types
- Invalid bind parameter (1)
- Cannot prepare statement
- The 'dialectClass' '{className}' must implement Phalcon\Db\D
- Savepoints are not supported by this database adapter
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/e10c1c15674a02fc.
Report an issue: GitHub.