prestodb/presto · error · PrestoException

INVALID_FUNCTION_ARGUMENT

INVALID_FUNCTION_ARGUMENT

Error message

zorder function requires a ROW type

What it means

The zorder() SQL function computes a Z-order key from a ROW-typed argument. If the resolved type T is not a RowType (e.g. a scalar was passed or the binding produced a non-row type), it throws INVALID_FUNCTION_ARGUMENT since Z-ordering requires multiple named fields to interleave.

Source

Thrown at presto-iceberg/src/main/java/com/facebook/presto/iceberg/function/IcebergZOrderFunctions.java:136

        return ZOrderByteUtils.longToOrderedBytes(value);
    }

    /**
     * Computes Z-order value from a ROW of columns.
     * Usage: zorder(ROW(col1, col2, col3, ...))
     *
     * @param rowType The type information for the row
     * @param rowBlock The row block containing the column values
     * @return The interleaved Z-order binary value
     */
    @ScalarFunction("zorder")
    @TypeParameter("T")
    @SqlType(StandardTypes.VARBINARY)
    @SqlNullable
    public static Slice zorder(@TypeParameter("T") Type rowType, @SqlType("T") Block rowBlock)
    {
        if (!(rowType instanceof RowType)) {
            throw new PrestoException(INVALID_FUNCTION_ARGUMENT, "zorder function requires a ROW type");
        }

        RowType row = (RowType) rowType;
        List<RowType.Field> fields = row.getFields();
        int fieldCount = fields.size();

        if (fieldCount == 0) {
            return Slices.wrappedBuffer(new byte[0]);
        }

        // Convert each field to ordered bytes based on its type
        Slice[] columnBytes = new Slice[fieldCount];
        int totalSize = 0;

        for (int i = 0; i < fieldCount; i++) {
            Type fieldType = fields.get(i).getType();

            if (rowBlock.isNull(i)) {

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Wrap the arguments in a row: zorder(CAST(ROW(a, b) AS ROW(x <type>, y <type>))).
  2. Verify the column used in zorder is declared as a ROW type in the table schema.
  3. Check function binding — ensure the @TypeParameter T is bound to a row type, not a scalar.

Example fix

// before
SELECT zorder(x, y) FROM t;
// after
SELECT zorder(CAST(ROW(x, y) AS ROW(a double, b double))) FROM t;
Defensive patterns

Strategy: type-guard

Validate before calling

boolean rowTyped(Type t) { return t instanceof RowType; }
// SQL-side check before clustering: DESCRIBE table; ensure column is row(...)

Type guard

boolean isRowTyped(Type t) {
    return t instanceof RowType;
}

Try / catch

try { result = session.getMetadata().getFunctionRegistry()...zorder(...); } catch (PrestoException e) { if (e.getErrorCode() == INVALID_FUNCTION_ARGUMENT.toErrorCode()) { /* wrap args in ROW(...) */ } throw e; }

Prevention

When it happens

Trigger: Calling zorder(col) where col is not a row/struct type — e.g. zorder(a, b) misuse or a bind that resolves T to a primitive instead of row(...).

Common situations: Users writing ORDER BY zorder(x, y) expecting multi-arg support; clustering DDL against tables whose column was changed from a struct to a scalar.

Related errors


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