{"record":{"id":"94009b2831828168","repo":"apache/beam","slug":"could-not-parse-sort-modifiers-in-expected-asc-desc-nulls","errorCode":null,"errorMessage":"Could not parse sort modifiers '{}' in '{}'. Expected: [asc|desc] [nulls first|nulls last].","messagePattern":"Could not parse sort modifiers '(.+?)' in '(.+?)'\\. Expected: \\[asc\\|desc\\] \\[nulls first\\|nulls last\\]\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/iceberg/src/main/java/org/apache/beam/sdk/io/iceberg/SortOrderUtils.java","lineNumber":83,"sourceCode":"      }\n    }\n    return builder.build();\n  }\n\n  private static ParsedSortField parse(String field) {\n    field = field.trim();\n    int splitAt = findTopLevelWhitespace(field);\n    String termStr = (splitAt < 0 ? field : field.substring(0, splitAt)).trim();\n    String rest = (splitAt < 0 ? \"\" : field.substring(splitAt)).trim();\n\n    Term term = PartitionUtils.toIcebergTerm(termStr);\n    boolean ascending = true;\n    @Nullable NullOrder nullOrder = null;\n\n    if (!rest.isEmpty()) {\n      Matcher matcher = MODIFIERS.matcher(rest);\n      if (!matcher.matches()) {\n        throw new IllegalArgumentException(\n            \"Could not parse sort modifiers '\"\n                + rest\n                + \"' in '\"\n                + field\n                + \"'. Expected: [asc|desc] [nulls first|nulls last].\");\n      }\n      String dir = matcher.group(\"dir\");\n      if (dir != null) {\n        ascending = dir.toLowerCase(Locale.ROOT).equals(\"asc\");\n      }\n      String nulls = matcher.group(\"nulls\");\n      if (nulls != null) {\n        nullOrder =\n            nulls.toLowerCase(Locale.ROOT).equals(\"first\")\n                ? NullOrder.NULLS_FIRST\n                : NullOrder.NULLS_LAST;\n      }\n    }","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/iceberg/src/main/java/org/apache/beam/sdk/io/iceberg/SortOrderUtils.java#L65-L101","documentation":"SortOrderUtils.parse builds an Iceberg SortOrder from a string spec like 'id asc nulls last'. When the modifier suffix of a field expression (e.g. 'desc nulls first') fails the MODIFIERS regex, it throws IllegalArgumentException with this message, echoing the bad modifiers and the full field expression.","triggerScenarios":"Passing a sort field string whose direction/null-order suffix doesn't match `[asc|desc] [nulls first|nulls last]` — e.g. 'name ascending', 'id DESC NULLS FIRST' with case handling the regex rejects, extra tokens ('id desc nulls first extra'), or misspellings ('nuls last').","commonSituations":"Configuring IcebergIO sort orders via pipeline options/CLI where whitespace or typos slip in; copy-pasted SQL-style ORDER BY clauses ('ORDER BY' keyword, comma handling) pasted into the spec string; locale or case differences.","solutions":["Use only the accepted tokens: field name optionally followed by 'asc' or 'desc', optionally followed by 'nulls first' or 'nulls last' (e.g. 'id desc nulls last')","Remove extra words/commas so each field spec is a single expression ('id asc', not 'ORDER BY id asc')","Check exact spelling and casing expected by SortOrderUtils, and trim stray whitespace before parsing"],"exampleFix":"// before\nString spec = \"id DESC NULLS FIRST\"; // rejected by MODIFIERS regex\n// after\nString spec = \"id desc nulls first\";","handlingStrategy":"validation","validationCode":"private static final java.util.regex.Pattern MODIFIERS_OK =\n    java.util.regex.Pattern.compile(\"(asc|desc)?(\\\\s+nulls\\\\s+(first|last))?\\\\s*\");\n\nvoid checkSortField(String field) {\n  String[] parts = field.trim().split(\"\\\\s+\", 2);\n  String rest = parts.length > 1 ? parts[1] : \"\";\n  if (!rest.isEmpty() && !MODIFIERS_OK.matcher(rest).matches()) {\n    throw new IllegalArgumentException(\"Bad sort modifiers in: \" + field);\n  }\n}","typeGuard":"boolean isValidSortField(String field) {\n  return field != null && field.matches(\"\\\\w+\\\\s*(asc|desc)?(\\\\s+nulls\\\\s+(first|last))?\\\\s*\");\n}","tryCatchPattern":"try {\n  SortOrder order = SortOrderUtils.parsed(spec);\n} catch (IllegalArgumentException e) {\n  // log e.getMessage(), fix config or fall back to default sort order\n}","preventionTips":["Validate sort spec strings against the `[asc|desc] [nulls first|nulls last]` grammar before submitting pipeline options","Avoid pasting SQL ORDER BY clauses verbatim into sort order configs","Trim and normalize whitespace/casing of sort spec strings","Add unit tests covering each modifier form (asc/desc x nulls first/nulls last)"],"tags":["iceberg","illegal-argument","parsing","sort-order"],"backgroundTag":"invalid-argument-format","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}