{"record":{"id":"9bbb5f5a28804f93","repo":"apache/druid","slug":"ambiguous-directions-s-and-s","errorCode":null,"errorMessage":"Ambiguous directions[%s] and [%s]","messagePattern":"Ambiguous directions\\[(.+?)\\] and \\[(.+?)\\]","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/groupby/orderby/OrderByColumnSpec.java","lineNumber":82,"sourceCode":"\n    @JsonValue\n    @Override\n    public String toString()\n    {\n      return StringUtils.toLowerCase(this.name());\n    }\n\n    @JsonCreator\n    public static Direction fromString(String name)\n    {\n      final String upperName = StringUtils.toUpperCase(name);\n      Direction direction = STUPID_ENUM_MAP.get(upperName);\n\n      if (direction == null) {\n        for (Direction dir : Direction.values()) {\n          if (dir.name().startsWith(upperName)) {\n            if (direction != null) {\n              throw new ISE(\"Ambiguous directions[%s] and [%s]\", direction, dir);\n            }\n            direction = dir;\n          }\n        }\n      }\n\n      return direction;\n    }\n  }\n\n  public static final StringComparator DEFAULT_DIMENSION_ORDER = StringComparators.LEXICOGRAPHIC;\n\n  private final String dimension;\n  private final Direction direction;\n  private final StringComparator dimensionComparator;\n\n  @JsonCreator\n  public OrderByColumnSpec(","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/groupby/orderby/OrderByColumnSpec.java#L64-L100","documentation":"OrderByColumnSpec.fromString parses a direction string (e.g. \"asc\", \"desc\", \"ascending\") by prefix-matching against Direction enum names. If the input prefix matches more than one Direction value, the parse is ambiguous and this ISE is thrown instead of silently picking one.","triggerScenarios":"Calling OrderByColumnSpec.fromString or constructing a spec from a JSON direction string that is a prefix of multiple Direction names (e.g. a string starting with \"d\" that matches both DESCENDING and another value, or any non-unique prefix).","commonSituations":"Hand-written native JSON queries using abbreviated direction strings like \"d\" or \"de\", user-supplied sort input passed through from an application, or typos in direction names in serialized query specs.","solutions":["Use the full, unambiguous direction name: \"ascending\" (or \"ASC\") / \"descending\" (or \"DESC\")","Use an exact enum value from STUPID_ENUM_MAP (case-insensitive) rather than a prefix","Validate user-provided direction strings against Direction.values() before constructing the spec"],"exampleFix":"// before\nOrderByColumnSpec.fromString(\"myCol\", \"d\") // ambiguous\n// after\nOrderByColumnSpec.fromString(\"myCol\", \"descending\")","handlingStrategy":"type-guard","validationCode":"Direction parseDirection(String s) {\n  String u = s.toUpperCase(Locale.ROOT);\n  if (\"ASCENDING\".startsWith(u)) return Direction.ASCENDING;\n  if (\"DESCENDING\".startsWith(u)) return Direction.DESCENDING;\n  throw new IllegalArgumentException(\"Ambiguous or invalid direction: \" + s);\n}","typeGuard":"boolean isExplicitDirection(String s) {\n  String u = s == null ? \"\" : s.toUpperCase(Locale.ROOT);\n  return u.equals(\"ASC\") || u.equals(\"ASCENDING\") || u.equals(\"DESC\") || u.equals(\"DESCENDING\");\n}","tryCatchPattern":"try {\n  spec = OrderByColumnSpec.fromString(col, dirStr);\n} catch (IllegalStateException e) {\n  if (e.getMessage().startsWith(\"Ambiguous directions\")) {\n    spec = OrderByColumnSpec.fromString(col, \"DESCENDING\"); // or surface a validation error to the user\n  } else throw e;\n}","preventionTips":["Always pass full direction names (ascending/descending) or exact enum values in query JSON","Validate user-supplied sort strings against the Direction enum before building specs","Avoid prefix-style abbreviations in serialized queries"],"tags":["parsing","enum","order-by","ambiguous-input"],"backgroundTag":"invalid-enum-value","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}