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

  1. Check the column's type with `DESCRIBE <table>` or `SELECT typeof(col) ...` and confirm it is ARRAY or MAP before unnesting.
  2. Unnest the field of the ROW type instead, or access the array/map member: e.g. `UNNEST(t.row_field.array_field)`.
  3. Cast or wrap the value: use `sequence()`/`split()`/`map_values()` etc. to produce an ARRAY from the actual data.
  4. 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

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


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/df5cc504c185fcd3. Report an issue: GitHub.