{"record":{"id":"b0879ac2e0d5ea28","repo":"hasura/graphql-engine","slug":"expected-number-for-side-hand-value-of-compariso","errorCode":null,"errorMessage":"Expected number for {side}-hand value of comparison operation","messagePattern":"Expected number for (.+?)-hand value of comparison operation","errorType":"error_code","errorClass":"ConditionError","httpStatus":null,"severity":"error","filePath":"v3/crates/auth/authorization-rules/src/condition.rs","lineNumber":23,"sourceCode":"use hasura_authn_core::{SessionVariableName, SessionVariables};\n\nuse crate::ConditionCache;\nuse metadata_resolve::{\n    BinaryOperation, Condition, ConditionHash, Conditions, UnaryOperation, ValueExpression,\n};\nuse open_dds::query::ArgumentName;\n\n#[derive(Debug, PartialEq, Eq, thiserror::Error)]\npub enum ConditionError {\n    #[error(\"Session variable not found: {name}\")]\n    SessionVariableNotFound { name: SessionVariableName },\n    #[error(\"Serde error: {error}\")]\n    SerdeError { error: String },\n    #[error(\"Condition {condition_hash} not found\")]\n    ConditionNotFound { condition_hash: ConditionHash },\n    #[error(\"Expected array or null for right-hand value of contains operation\")]\n    ExpectedArrayOrNullForContains,\n    #[error(\"Expected number for {side}-hand value of comparison operation\")]\n    ExpectedNumberForComparison { side: Side },\n    #[error(\n        \"Number for {side}-hand value of comparison operation is outside precision or range of a double-precision float\"\n    )]\n    NumberOutOfRange { side: Side },\n    #[error(\n        \"Tried to combine a predicate with a literal in argument presets for argument {argument_name}\"\n    )]\n    CouldNotCombinePredicateAndLiteralArgumentPresets { argument_name: ArgumentName },\n}\n\n// evaluate conditions used in permissions\nfn evaluate_condition(\n    condition: &Condition,\n    session_variables: &SessionVariables,\n) -> Result<bool, ConditionError> {\n    match condition {\n        Condition::All(conditions) => conditions.iter().try_fold(true, |acc, condition| {","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/v3/crates/auth/authorization-rules/src/condition.rs#L5-L41","documentation":"For comparison operations in authorization rules, at least one side must resolve to a number when required by the operator (e.g. gt/lt on numeric columns). If the operand on the indicated side (left or right) is a non-numeric value — a string session variable, null, or a wrongly typed literal — ConditionError::ExpectedNumberForComparison is thrown, identifying which side failed.","triggerScenarios":"A rule comparing a numeric column against a session variable whose claim is a string (`\\\"42\\\"`), or comparing a string column with a numeric literal; session variable missing-but-defaulted to a non-numeric value.","commonSituations":"JWT numeric claims serialized as strings by the auth server; metadata literals written as strings; schema type changes (column became numeric) without updating the rule.","solutions":["Check the reported `{side}` and make that operand a number: fix the JWT claim to be a JSON number, or the metadata literal to be unquoted","Align the rule's operand types with the column type in the data source schema","Re-apply metadata after schema type changes"],"exampleFix":"# before\n{ operator: gt, column: age, value: { session: x_hasura_min_age } }  # claim = \"18\"\n# after: emit claim as JSON number\n\"x-hasura-min-age\": 18","handlingStrategy":"type-guard","validationCode":"const v = resolveOperand(rule.value);\nif (rule.operator === 'gt' && typeof v !== 'number') throw new Error(`${rule.side} operand must be a number`);","typeGuard":"const isNumber = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v);","tryCatchPattern":"null","preventionTips":["Serialize numeric claims as JSON numbers, not strings","Match operand types to column types in rules","Re-validate rules after schema type changes"],"tags":["auth","authorization","comparison","type-mismatch","rust","hasura"],"backgroundTag":"authorization-type-mismatch","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}