apache/druid · error · IllegalStateException
Ambiguous directions
Error message
Ambiguous directions[%s] and [%s]
What it means
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.
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
Example fix
// before
OrderByColumnSpec.fromString("myCol", "d") // ambiguous
// after
OrderByColumnSpec.fromString("myCol", "descending") Defensive patterns
Strategy: type-guard
Validate before calling
Direction parseDirection(String s) {
String u = s.toUpperCase(Locale.ROOT);
if ("ASCENDING".startsWith(u)) return Direction.ASCENDING;
if ("DESCENDING".startsWith(u)) return Direction.DESCENDING;
throw new IllegalArgumentException("Ambiguous or invalid direction: " + s);
} Type guard
boolean isExplicitDirection(String s) {
String u = s == null ? "" : s.toUpperCase(Locale.ROOT);
return u.equals("ASC") || u.equals("ASCENDING") || u.equals("DESC") || u.equals("DESCENDING");
} Try / catch
try {
spec = OrderByColumnSpec.fromString(col, dirStr);
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("Ambiguous directions")) {
spec = OrderByColumnSpec.fromString(col, "DESCENDING"); // or surface a validation error to the user
} else throw e;
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Argument [ ] is not a valid URI
- defensive
- Expected key [ ] to be referring to one of the values [ ]…
- function ' ' is not defined.
- Illegal segmentId format
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/9bbb5f5a28804f93.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/query/groupby/orderby/OrderByColumnSpec.java:82
@JsonValue
@Override
public String toString()
{
return StringUtils.toLowerCase(this.name());
}
@JsonCreator
public static Direction fromString(String name)
{
final String upperName = StringUtils.toUpperCase(name);
Direction direction = STUPID_ENUM_MAP.get(upperName);
if (direction == null) {
for (Direction dir : Direction.values()) {
if (dir.name().startsWith(upperName)) {
if (direction != null) {
throw new ISE("Ambiguous directions[%s] and [%s]", direction, dir);
}
direction = dir;
}
}
}
return direction;
}
}
public static final StringComparator DEFAULT_DIMENSION_ORDER = StringComparators.LEXICOGRAPHIC;
private final String dimension;
private final Direction direction;
private final StringComparator dimensionComparator;
@JsonCreator
public OrderByColumnSpec(View on GitHub (pinned to 9b90983fd2)