{"record":{"id":"e10c1c15674a02fc","repo":"phalcon/cphalcon","slug":"matched-parameter-was-not-found-in-parameters-list","errorCode":null,"errorMessage":"Matched parameter was not found in parameters list","messagePattern":"Matched parameter was not found in parameters list","errorType":"exception","errorClass":"Phalcon\\Db\\Exceptions\\MatchedParameterNotFound","httpStatus":null,"severity":"error","filePath":"phalcon/Db/Adapter/Pdo/AbstractPdo.zep","lineNumber":366,"sourceCode":"     *     )\n     * );\n     *```\n     */\n    public function convertBoundParams( string sql, array params = []) -> array\n    {\n        var boundSql, placeHolders, bindPattern, matches, setOrder, placeMatch,\n            value;\n\n        let placeHolders = [],\n            bindPattern = self::BIND_PATTERN,\n            matches = null,\n            setOrder = 2;\n\n        if preg_match_all(bindPattern, sql, matches, setOrder) {\n            for placeMatch in matches {\n                if !fetch value, params[placeMatch[1]] {\n                    if unlikely !isset placeMatch[2] {\n                        throw new MatchedParameterNotFound();\n                    }\n\n                    if unlikely !fetch value, params[placeMatch[2]] {\n                        throw new MatchedParameterNotFound();\n                    }\n                }\n\n                let placeHolders[] = value;\n            }\n\n            let boundSql = preg_replace(bindPattern, \"?\", sql);\n        } else {\n            let boundSql = sql;\n        }\n\n        return [\n            \"sql\"    : boundSql,\n            \"params\" : placeHolders","sourceCodeStart":348,"sourceCodeEnd":384,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Db/Adapter/Pdo/AbstractPdo.zep#L348-L384","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n$sql = 'SELECT * FROM users WHERE city = :city:';\n$params = ['town' => 'Berlin'];\n$result = $connection->convertBoundParams($sql, $params);\n\n// after\n$sql = 'SELECT * FROM users WHERE city = :city:';\n$params = ['city' => 'Berlin'];\n$result = $connection->convertBoundParams($sql, $params);","handlingStrategy":"validation","validationCode":"// mirror of the internal BIND_PATTERN '/\\?([0-9]+)|:([a-zA-Z0-9_]+):/'\npreg_match_all('/\\?([0-9]+)|:([a-zA-Z0-9_]+):/', $sql, $m, PREG_SET_ORDER);\nforeach ($m as $match) {\n    $key = $match[1] !== '' ? (int) $match[1] : $match[2];\n    if (!array_key_exists($key, $params)) {\n        throw new InvalidArgumentException(\"SQL placeholder '{$key}' missing from params\");\n    }\n}\n$connection->convertBoundParams($sql, $params);","typeGuard":null,"tryCatchPattern":"use Phalcon\\Db\\Exceptions\\MatchedParameterNotFound;\n\ntry {\n    [$sql, $values] = $connection->convertBoundParams($sql, $params);\n} catch (MatchedParameterNotFound $e) {\n    throw new RuntimeException('SQL/params mismatch: ' . $e->getMessage() . ' in: ' . $sql, 0, $e);\n}","preventionTips":["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"],"tags":["php","phalcon","db","bind","sql","placeholder","parameter-mismatch"],"backgroundTag":"missing-bound-parameter","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}