prestodb/presto · error · PrestoException
DATATYPE_MISMATCH
DATATYPE_MISMATCH
Error message
Expected row filter for '%s' to be of type BOOLEAN, but was %s
What it means
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.
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java:5374
analysis,
expression,
warningCollector);
}
catch (PrestoException e) {
throw new PrestoException(e::getErrorCode, format("Invalid row filter for '%s: %s'", name, e.getMessage()), e);
}
finally {
analysis.unregisterTableForRowFiltering(name, currentIdentity);
}
verifyNoAggregateWindowOrGroupingFunctions(analysis.getFunctionHandles(), functionAndTypeResolver, expression, format("Row filter for '%s'", name));
analysis.recordSubqueries(expression, expressionAnalysis);
Type actualType = expressionAnalysis.getType(expression);
if (!actualType.equals(BOOLEAN)) {
if (!metadata.getFunctionAndTypeManager().canCoerce(actualType, BOOLEAN)) {
throw new PrestoException(DATATYPE_MISMATCH, format("Expected row filter for '%s' to be of type BOOLEAN, but was %s", name, actualType), null);
}
analysis.addCoercion(expression, BOOLEAN, false);
}
analysis.addRowFilter(table, expression);
}
private void analyzeColumnMask(String currentIdentity, Table table, QualifiedObjectName tableName, ColumnMetadata columnMetadata, Scope scope, ViewExpression mask)
{
String column = columnMetadata.getName();
if (analysis.hasColumnMask(tableName, column, currentIdentity)) {
throw new PrestoException(INVALID_COLUMN_MASK, format("Column mask for '%s.%s' is recursive", tableName, column), null);
}
Expression expression;
try {
expression = sqlParser.createExpression(mask.getExpression(), createParsingOptions(session));View on GitHub (pinned to 55bb57d202)
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
Example fix
// before "is_active_user_id" // after "is_active = true"
Defensive patterns
Strategy: validation
Validate before calling
// Check the filter analyzes to a BOOLEAN (or coercible) type before installing:
Type actual = expressionAnalysis.getType(expression);
if (!actual.equals(BOOLEAN) && !metadata.getFunctionAndTypeManager().canCoerce(actual, BOOLEAN)) {
throw new IllegalArgumentException("Row filter must be boolean, got: " + actual);
} Type guard
boolean isBooleanFilter(Type t, FunctionAndTypeManager ftm) {
return t.equals(BOOLEAN) || ftm.canCoerce(t, BOOLEAN);
} Try / catch
try { session.execute("SELECT * FROM " + table); }
catch (PrestoException e) {
if ("DATATYPE_MISMATCH".equals(e.getErrorCode().getName()) && e.getMessage().contains("row filter")) {
throw new PolicyConfigurationException("Row filter must be a boolean predicate", e);
} else { throw e; }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- ELASTICSEARCH_TYPE_MISMATCH
- INVALID_ROW_FILTER
- BIGQUERY_UNSUPPORTED_TYPE_FOR_VARBINARY
- Error setting up SSL:
- Next URI host and port %s are different than current %s
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/fc1a0d673807ed6c.
Report an issue: GitHub.