{"record":{"id":"fc1a0d673807ed6c","repo":"prestodb/presto","slug":"datatype-mismatch-fc1a0d","errorCode":"DATATYPE_MISMATCH","errorMessage":"Expected row filter for '%s' to be of type BOOLEAN, but was %s","messagePattern":"Expected row filter for '(.+?)' to be of type BOOLEAN, but was (.+?)","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"error","filePath":"presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java","lineNumber":5374,"sourceCode":"                        analysis,\n                        expression,\n                        warningCollector);\n            }\n            catch (PrestoException e) {\n                throw new PrestoException(e::getErrorCode, format(\"Invalid row filter for '%s: %s'\", name, e.getMessage()), e);\n            }\n            finally {\n                analysis.unregisterTableForRowFiltering(name, currentIdentity);\n            }\n\n            verifyNoAggregateWindowOrGroupingFunctions(analysis.getFunctionHandles(), functionAndTypeResolver, expression, format(\"Row filter for '%s'\", name));\n\n            analysis.recordSubqueries(expression, expressionAnalysis);\n\n            Type actualType = expressionAnalysis.getType(expression);\n            if (!actualType.equals(BOOLEAN)) {\n                if (!metadata.getFunctionAndTypeManager().canCoerce(actualType, BOOLEAN)) {\n                    throw new PrestoException(DATATYPE_MISMATCH, format(\"Expected row filter for '%s' to be of type BOOLEAN, but was %s\", name, actualType), null);\n                }\n\n                analysis.addCoercion(expression, BOOLEAN, false);\n            }\n\n            analysis.addRowFilter(table, expression);\n        }\n\n        private void analyzeColumnMask(String currentIdentity, Table table, QualifiedObjectName tableName, ColumnMetadata columnMetadata, Scope scope, ViewExpression mask)\n        {\n            String column = columnMetadata.getName();\n            if (analysis.hasColumnMask(tableName, column, currentIdentity)) {\n                throw new PrestoException(INVALID_COLUMN_MASK, format(\"Column mask for '%s.%s' is recursive\", tableName, column), null);\n            }\n\n            Expression expression;\n            try {\n                expression = sqlParser.createExpression(mask.getExpression(), createParsingOptions(session));","sourceCodeStart":5356,"sourceCodeEnd":5392,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java#L5356-L5392","documentation":"A row filter acts as a boolean predicate appended to queries against the table, so its analyzed type must be BOOLEAN (or coercible to BOOLEAN). If the expression's type is neither BOOLEAN nor coercible, Presto throws DATATYPE_MISMATCH with this message.","triggerScenarios":"A row filter expression like `user_id` (integer) or `status` (varchar) without a comparison; thrown in analyzeRowFilter after ExpressionAnalysis when canCoerce(actualType, BOOLEAN) is false.","commonSituations":"Defining a filter as a bare column reference assuming implicit truthiness; forgetting `= TRUE` / `IS TRUE`; filters returning int codes instead of boolean; copy-pasting projection expressions into filter policies.","solutions":["Wrap the expression in an explicit boolean comparison, e.g. `status = 'ACTIVE'`","Cast the result: `CAST(col AS boolean)` if the cast is valid","Fix the policy store so the registered ViewExpression is a predicate, not a value"],"exampleFix":"// before\n\"is_active_user_id\"\n// after\n\"is_active = true\"","handlingStrategy":"validation","validationCode":"// Check the filter analyzes to a BOOLEAN (or coercible) type before installing:\nType actual = expressionAnalysis.getType(expression);\nif (!actual.equals(BOOLEAN) && !metadata.getFunctionAndTypeManager().canCoerce(actual, BOOLEAN)) {\n    throw new IllegalArgumentException(\"Row filter must be boolean, got: \" + actual);\n}","typeGuard":"boolean isBooleanFilter(Type t, FunctionAndTypeManager ftm) {\n    return t.equals(BOOLEAN) || ftm.canCoerce(t, BOOLEAN);\n}","tryCatchPattern":"try { session.execute(\"SELECT * FROM \" + table); }\ncatch (PrestoException e) {\n    if (\"DATATYPE_MISMATCH\".equals(e.getErrorCode().getName()) && e.getMessage().contains(\"row filter\")) {\n        throw new PolicyConfigurationException(\"Row filter must be a boolean predicate\", e);\n    } else { throw e; }\n}","preventionTips":["Always end filter expressions with an explicit boolean comparison","Never register bare column references as filters","Test filter type by running `SELECT <filter> FROM table LIMIT 1` before deploy"],"tags":["security","row-filter","type-mismatch","boolean"],"backgroundTag":"row-filter-not-boolean","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}