bazelbuild/bazel · error · EvalException
unsupported comparison: %s <=> %s
Error message
unsupported comparison: %s <=> %s
What it means
Thrown when a Starlark ordered comparison operator (<, <=, >, >=) is applied to two values whose types cannot be ordered against each other. EvalUtils.compare catches the ClassCastException raised by Starlark.compareUnchecked and rethrows it as an EvalException, so the user sees 'unsupported comparison: T1 <=> T2'. Only same-type ordered values (and int/float mixtures) are comparable in Starlark.
Source
Thrown at src/main/java/net/starlark/java/eval/EvalUtils.java:408
}
}
if (y instanceof HasBinary) {
Object z = ((HasBinary) y).binaryOp(op, x, false);
if (z != null) {
return z;
}
}
throw Starlark.errorf(
"unsupported binary operation: %s %s %s", Starlark.type(x), op, Starlark.type(y));
}
// Defines the behavior of the language's ordered comparison operators (< <= => >).
private static int compare(Object x, Object y) throws EvalException {
try {
return Starlark.compareUnchecked(x, y);
} catch (ClassCastException ex) {
throw new EvalException(ex.getMessage());
}
}
private static String repeatString(String s, StarlarkInt in) throws EvalException {
int n = in.toInt("repeat");
if (n <= 0) {
return "";
} else if ((long) s.length() * (long) n > Integer.MAX_VALUE) {
// Would exceed max length of a java String.
throw Starlark.errorf("excessive repeat (%d * %d characters)", s.length(), n);
} else {
return s.repeat(n);
}
}
/** Evaluates a unary operation. */
static Object unaryOp(TokenKind op, Object x) throws EvalException {
switch (op) {View on GitHub (pinned to e6e199d060)
Solutions
- Ensure both operands have the same type before comparing; convert explicitly (str(x) < str(y), int(x) < int(y)).
- If comparing containers, compare element-wise or via a key function that yields a uniform type (e.g. sorted(items, key=str)).
- For 'unset' checks, test identity/emptiness (x == None, if not x) instead of ordering against None.
- Catch EvalException at the Java call site and surface a domain-specific message.
Example fix
# before
if version < 2: # version is "1.2.3"
...
# after
if int(version.split(".")[0]) < 2:
... Defensive patterns
Strategy: validation
Validate before calling
# before comparing, ensure both sides are the same type
def safe_lt(x, y):
if type(x) != type(y) and not ((type(x) == "int" and type(y) == "float") or (type(x) == "float" and type(y) == "int")):
fail("cannot compare %s with %s" % (type(x), type(y)))
return x < y Type guard
def is_comparable_pair(x, y):
t = (type(x), type(y))
return t[0] == t[1] or set(t) == {"int", "float"} Prevention
- Never use < > on values whose types come from different sources; normalize first.
- Prefer == / != for 'is it set' checks instead of ordering against None.
- Sort heterogeneous data with an explicit key= that maps to one type.
When it happens
Trigger: Evaluating 1 < "a", [1,2] < (1,2), None < 1, or any < between values of different Starlark types where neither side is an int/float pair. Also fires when a user-defined Comparable Starlark value is compared against an unrelated type.
Common situations: Sorting or comparing heterogeneous lists (e.g. sorted(["b", 1])), validating input where a string arrives where an int was expected, comparing depsets/tuples/lists across types, or comparing None to a number as a 'is it unset' idiom borrowed from other languages.
Related errors
- unsupported comparison: %s <=> %s
- got %s for '%%%c' format, want int or float
- cannot compare self-referential or overly nested data struct
- unsupported comparison: %s <=> %s
- This converter doesn't support Starlark reversal.
AI-assisted analysis of bazelbuild/bazel@e6e199d060 (2026-08-14).
Data as JSON: /api/errors/4b92fcdbc9861e7a.
Report an issue: GitHub.