prestodb/presto · error · IllegalArgumentException

Unable to parse sort field: [%s]

Error message

Unable to parse sort field: [%s]

What it means

parseSortField applies a regex (PATTERN) to each sorted_by entry to extract identifier, ordering (ASC/DESC), optional null ordering, and transform. Entries that don't match the grammar throw IllegalArgumentException("Unable to parse sort field: [%s]") which surfaces from parseSortFields. It enforces the strict syntax of the sorted_by property.

Source

Thrown at presto-iceberg/src/main/java/com/facebook/presto/iceberg/SortFieldUtils.java:84

        for (SortField field : sortOrder.fields()) {
            if (!baseColumnFieldIds.contains(field.sourceId())) {
                throw new PrestoException(COLUMN_NOT_FOUND, "Column not found: " + schema.findColumnName(field.sourceId()));
            }
        }

        return sortOrder;
    }

    public static void parseSortFields(SortOrderBuilder<?> sortOrderBuilder, List<String> fields)
    {
        fields.forEach(field -> parseSortField(sortOrderBuilder, field));
    }

    private static void parseSortField(SortOrderBuilder<?> builder, String field)
    {
        Matcher matcher = PATTERN.matcher(field);
        if (!matcher.matches()) {
            throw new IllegalArgumentException(format("Unable to parse sort field: [%s]", field));
        }

        String columnName = fromIdentifierToColumn(matcher.group("identifier"));
        boolean ascending;
        String ordering = firstNonNull(matcher.group("ordering"), "ASC").toUpperCase(Locale.ENGLISH);

        switch (ordering) {
            case "ASC":
                ascending = true;
                break;
            case "DESC":
                ascending = false;
                break;
            default:
                throw new IllegalStateException("Unexpected ordering value: " + ordering);
        }

        String nullOrderDefault = ascending ? "FIRST" : "LAST";

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Rewrite each entry in the accepted form: identifier [ASC|DESC] with optional transform, e.g. 'col ASC', 'truncate(10, col) DESC'
  2. Remove surrounding quotes/spaces accidentally included inside the array element
  3. Replace complex expressions with plain column names plus Iceberg transforms
  4. Create without sorted_by, then add the property incrementally, testing one field at a time to isolate the malformed entry

Example fix

// before
WITH (sorted_by = ARRAY['LOWER(name) ASC'])
// after
WITH (sorted_by = ARRAY['name ASC'])
Defensive patterns

Strategy: validation

Validate before calling

Pattern P = Pattern.compile("(?<identifier>\\S+?)(\\s+(?<ordering>ASC|DESC))?(\\s+NULLS\\s+(?<nulls>FIRST|LAST))?\\s*$");
for (String f : sortedBy) {
    if (!P.matcher(f).matches()) throw new IllegalArgumentException("Unable to parse sort field: [" + f + "]");
}

Type guard

boolean isValidSortField(String f) {
    return f != null && f.matches("^\\S+(\\s+(ASC|DESC))?(\\s+NULLS\\s+(FIRST|LAST))?\\s*$");
}

Try / catch

try { /* CREATE TABLE with sorted_by */ } catch (Exception e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Unable to parse sort field")) {
        // offending entry is inside the brackets; fix syntax and retry
    } else { throw e; }
}

Prevention

When it happens

Trigger: CREATE TABLE ... WITH (sorted_by = ARRAY[...]) containing an entry that fails the regex — e.g. empty string, missing identifier, malformed transform like 'bucket(abc, col)', stray characters, or a completely free-form sort expression.

Common situations: Passing SQL ORDER BY expressions instead of the identifier grammar; quoting errors leaving extra quotes in the string; whitespace or case variants the pattern rejects; copying syntax from other engines (e.g. Spark CLUSTER BY).

Understand the failure class

Related errors


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