phalcon/cphalcon · error · InvalidUnaryExpression
Invalid SQL-unary expression
Error message
Invalid SQL-unary expression
What it means
getSqlExpressionUnary() throws InvalidUnaryExpression when a unary-op expression has neither a 'left' nor a 'right' key. The resolver first tries expression['left'] (rendered as 'left OP'), then expression['right'] ('OP right'); if both are absent there is no operand for the operator (NOT, IS NULL, etc.) and the compiler throws.
Source
Thrown at phalcon/Db/Dialect.zep:1429
final protected function getSqlExpressionUnaryOperations( array expression, string escapeChar = null, array bindCounts = []) -> string
{
var left, right;
/**
* Some unary operators use the left operand...
*/
if fetch left, expression["left"] {
return this->getSqlExpression(left, escapeChar, bindCounts) . " " . expression["op"];
}
/**
* ...Others use the right operand
*/
if fetch right, expression["right"] {
return expression["op"] . " " . this->getSqlExpression(right, escapeChar, bindCounts);
}
throw new InvalidUnaryExpression();
}
/**
* Resolve a WHERE clause
*
* @param array|string expression
* @param string|null escapeChar
* @param array bindCounts
*
* @return string
*/
final protected function getSqlExpressionWhere(var expression, string escapeChar = null, array bindCounts = []) -> string
{
var whereSql;
if typeof expression === "array" {
let whereSql = this->getSqlExpression(expression, escapeChar, bindCounts);
} else {View on GitHub (pinned to b7419de9cd)
Solutions
- Attach the operand under 'left' or 'right': ['type' => 'unary-op', 'op' => 'NOT ', 'right' => ['type' => 'qualified', 'name' => 'active']]
- For NULL checks prefer Query Builder conditions like where('active IS NULL') which build the unary expression correctly
- Validate unary nodes in your expression factory: require isset($node['left']) XOR isset($node['right'])
Example fix
// before
$expr = ['type' => 'unary-op', 'op' => 'NOT '];
// after
$expr = [
'type' => 'unary-op',
'op' => 'NOT ',
'right' => ['type' => 'qualified', 'name' => 'active'],
]; Defensive patterns
Strategy: validation
Validate before calling
if (($expr['type'] ?? null) === 'unary-op'
&& !isset($expr['left'])
&& !isset($expr['right'])
) {
throw new InvalidArgumentException('Unary expression requires a left or right operand');
} Type guard
function isCompleteUnaryExpression(array $expr): bool
{
return ($expr['type'] ?? null) !== 'unary-op'
|| isset($expr['left'])
|| isset($expr['right']);
} Try / catch
try {
$sql = $dialect->select($definition);
} catch (\Phalcon\Db\Exceptions\InvalidUnaryExpression $e) {
throw new InvalidArgumentException('Unary operator without operand', 0, $e);
} Prevention
- Create unary nodes via a helper that always attaches the operand
- For IS NULL / NOT conditions use Query Builder where() clauses
- Unit-test expression builders for edge cases where operands may be absent
When it happens
Trigger: Passing ['type' => 'unary-op', 'op' => 'NOT'] with no operand; operand stored under a wrong key ('operand', 'value'); nested expression construction that attaches the operand to a copy of the array that is later discarded.
Common situations: Building IS NULL / NOT conditions programmatically where the operand branch is skipped for edge cases; copy-pasted expression templates missing the operand key.
Related errors
- Invalid SQL-GROUP-BY expression
- Invalid SQL-list expression
- Invalid SQL-ORDER-BY expression
- The index 'tables' is required in the definition array
- The index 'columns' is required in the definition array
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/d055b7d215dc6cbd.
Report an issue: GitHub.