prestodb/presto · error · PrestoException
INVALID_FUNCTION_ARGUMENT
INVALID_FUNCTION_ARGUMENT
Error message
Cannot unnest type:
What it means
Presto throws a PrestoException with StandardErrorCode.INVALID_FUNCTION_ARGUMENT when an expression in an UNNEST clause has a type that is neither an ArrayType nor a MapType. UNNEST can only expand arrays (one output column of the element type) and maps (two output columns: key and value types); any other type cannot be unnested.
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java:1745
}
Type expressionType = expressionAnalysis.getType(expression);
if (expressionType instanceof ArrayType) {
Type elementType = ((ArrayType) expressionType).getElementType();
if (!SystemSessionProperties.isLegacyUnnest(session) && elementType instanceof RowType) {
((RowType) elementType).getFields().stream()
.map(field -> Field.newUnqualified(expression.getLocation(), field.getName(), field.getType()))
.forEach(outputFields::add);
}
else {
outputFields.add(Field.newUnqualified(expression.getLocation(), Optional.empty(), elementType));
}
}
else if (expressionType instanceof MapType) {
outputFields.add(Field.newUnqualified(expression.getLocation(), Optional.empty(), ((MapType) expressionType).getKeyType()));
outputFields.add(Field.newUnqualified(expression.getLocation(), Optional.empty(), ((MapType) expressionType).getValueType()));
}
else {
throw new PrestoException(StandardErrorCode.INVALID_FUNCTION_ARGUMENT, "Cannot unnest type: " + expressionType);
}
ImmutableList<Field> allFields = outputFields.build();
Set<SourceColumn> sourceColumns = analysis.getExpressionSourceColumns(expression);
for (int i = fieldsBefore; i < allFields.size(); i++) {
analysis.addSourceColumns(allFields.get(i), sourceColumns);
}
fieldsBefore = allFields.size();
}
if (node.isWithOrdinality()) {
outputFields.add(Field.newUnqualified(node.getLocation(), Optional.empty(), BIGINT));
}
return createAndAssignScope(node, scope, outputFields.build());
}
@Override
protected Scope visitLateral(Lateral node, Optional<Scope> scope)
{View on GitHub (pinned to 55bb57d202)
Solutions
- Check the column's type with `DESCRIBE <table>` or `SELECT typeof(col) ...` and confirm it is ARRAY or MAP before unnesting.
- Unnest the field of the ROW type instead, or access the array/map member: e.g. `UNNEST(t.row_field.array_field)`.
- Cast or wrap the value: use `sequence()`/`split()`/`map_values()` etc. to produce an ARRAY from the actual data.
- Catch PrestoException, check getErrorCode() == INVALID_FUNCTION_ARGUMENT and the 'Cannot unnest type:' prefix, and surface the offending type name to the user.
Example fix
-- before (labels is VARCHAR) SELECT v FROM t CROSS JOIN UNNEST(t.labels) AS x(v) // after SELECT x.v FROM t CROSS JOIN UNNEST(split(t.labels, ',')) AS x(v)
Defensive patterns
Strategy: type-guard
Validate before calling
try (ResultSet rs = stmt.executeQuery("SELECT typeof(col) FROM t LIMIT 1")) {
String t = rs.getString(1).toLowerCase();
if (!t.startsWith("array") && !t.startsWith("map")) {
throw new IllegalArgumentException("cannot unnest type " + t + "; expected array or map");
}
} Type guard
boolean isUnnestable(String prestoType) {
String t = prestoType == null ? "" : prestoType.toLowerCase();
return t.startsWith("array(") || t.startsWith("map(");
} Try / catch
try { runQuery(sql); } catch (PrestoException e) { if (e.getErrorCode() == StandardErrorCode.INVALID_FUNCTION_ARGUMENT.toErrorCodeCode() && e.getMessage().startsWith("Cannot unnest type:")) { castOrRewrite(sql, e.getMessage()); } else { throw e; } } Prevention
- Run DESCRIBE table or typeof(col) before writing UNNEST queries against unfamiliar schemas.
- Watch for schema migrations that change array columns to scalar or row types.
- Unnest nested fields explicitly (row.array_field) rather than assuming the outer column is a container.
When it happens
Trigger: Running `SELECT ... FROM t CROSS JOIN UNNEST(t.some_column) AS x(v)` where some_column is a row/varchar/int/etc. rather than ARRAY or MAP. The check happens in the analyzer after expression type inference: the final else branch throws.
Common situations: Schema changes turning an array column into a scalar/row type; misremembering a MAP column as an array (or vice versa) and destructuring it wrongly; connector type mapping producing ROW where the source was expected to be a list.
Related errors
- TYPE_MISMATCH
- INVALID_FUNCTION_ARGUMENT
- INVALID_FUNCTION_ARGUMENT
- INVALID_FUNCTION_ARGUMENT
- INVALID_FUNCTION_ARGUMENT
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/df5cc504c185fcd3.
Report an issue: GitHub.