{"record":{"id":"1b437ff518a633fa","repo":"phalcon/cphalcon","slug":"invalid-sql-order-by-expression","errorCode":null,"errorMessage":"Invalid SQL-ORDER-BY expression","messagePattern":"Invalid SQL-ORDER-BY expression","errorType":"exception","errorClass":"InvalidOrderByExpression","httpStatus":null,"severity":"error","filePath":"phalcon/Db/Dialect.zep","lineNumber":1330,"sourceCode":"     * Resolve an ORDER BY clause\n     *\n     * @param array|string expression\n     * @param string|null escapeChar\n     * @param array bindCounts\n     *\n     * @return string\n     */\n    final protected function getSqlExpressionOrderBy(var expression, string escapeChar = null,  array bindCounts = []) -> string\n    {\n        var field, fields, type, fieldSql = null;\n\n        if typeof expression === \"array\" {\n            let fields = [];\n\n            for field in expression {\n\n                if unlikely typeof field != \"array\" {\n                    throw new InvalidOrderByExpression();\n                }\n\n                let fieldSql = this->getSqlExpression(\n                    field[0],\n                    escapeChar,\n                    bindCounts\n                );\n\n                /**\n                 * In the numeric 1 position could be a ASC/DESC clause\n                 */\n                if fetch type, field[1] && type != \"\" {\n                    let fieldSql .= \" \" . type;\n                }\n\n                let fields[] = fieldSql;\n            }\n","sourceCodeStart":1312,"sourceCodeEnd":1348,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Db/Dialect.zep#L1312-L1348","documentation":"getSqlExpressionOrderBy() throws InvalidOrderByExpression when the orderBy definition is an array but one of its elements is not an array. Each element must be a two-part array: [expression, 'ASC'|'DESC'], where the first slot is itself a resolvable expression array. A plain string like 'name DESC' inside the array is rejected at this layer.","triggerScenarios":"Passing definition['orderBy'] = ['name DESC'] or ['id'] (strings) directly to Dialect::select(); mixing string and array entries in the orderBy array. The Query Builder parses orderBy strings into [expr, direction] pairs before reaching the dialect, so this fires mainly on hand-built definitions.","commonSituations":"Forwarding raw user sort parameters straight into a select() definition; porting SQL ORDER BY clause strings into the array-based API; inconsistent data shape between code paths that build orderBy.","solutions":["Convert each entry to [expression, direction] form: [['type' => 'raw', 'value' => 'name'], 'DESC']","Let Phalcon\\Db\\QueryBuilder->orderBy('name DESC') do the string parsing for you","Sanitize user-supplied sort input into [field, direction] pairs and whitelist the direction"],"exampleFix":"// before\n$definition['orderBy'] = ['name DESC', 'id'];\n\n// after\n$definition['orderBy'] = [\n    [['type' => 'raw', 'value' => 'name'], 'DESC'],\n    [['type' => 'raw', 'value' => 'id'], 'ASC'],\n];","handlingStrategy":"validation","validationCode":"foreach ($definition['orderBy'] ?? [] as $entry) {\n    if (!is_array($entry)) {\n        throw new InvalidArgumentException('Each ORDER BY entry must be [expr, direction]');\n    }\n}","typeGuard":"function isOrderByExpressionList(array $orderBy): bool\n{\n    foreach ($orderBy as $entry) {\n        if (!is_array($entry)) {\n            return false;\n        }\n    }\n    return true;\n}","tryCatchPattern":"try {\n    $sql = $dialect->select($definition);\n} catch (\\Phalcon\\Db\\Exceptions\\InvalidOrderByExpression $e) {\n    throw new InvalidArgumentException('Malformed ORDER BY definition', 0, $e);\n}","preventionTips":["Parse sort strings once into [expression, ASC|DESC] pairs and whitelist the direction","Use Query Builder->orderBy('name DESC') for string input","Never forward user sort input raw into a dialect definition"],"tags":["phalcon","sql","dialect","order-by","expression-array"],"backgroundTag":"invalid-sql-expression","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}