bazelbuild/bazel · error · ClassCastException
cannot compare self-referential or overly nested data struct
Error message
cannot compare self-referential or overly nested data structures %s and %s
What it means
Starlark.compareUnchecked compares same-type Comparable values by calling compareTo; a self-referential structure (a list containing itself) or one nested deeply enough makes the recursive comparison overflow the Java stack. The StackOverflowError is caught and converted to a ClassCastException with this message (a documented wart: ClassCastException is the channel for all cannot-compare errors), which callers like EvalUtils.compare then turn into an EvalException.
Source
Thrown at src/main/java/net/starlark/java/eval/Starlark.java:595
/**
* Defines the strict weak ordering of Starlark values used for sorting and the comparison
* operators.
*
* @throws ClassCastException on failure.
*/
static int compareUnchecked(Object x, Object y) {
if (sameType(x, y)) {
// Ordered? e.g. string, int, bool, float.
if (x instanceof Comparable) {
@SuppressWarnings("unchecked")
Comparable<Object> xcomp = (Comparable<Object>) x;
try {
return xcomp.compareTo(y);
} catch (StackOverflowError unused) {
// Wart: this particular error has nothing to do with class mismatch - but alas,
// Comparable interface uses ClassCastException for reporting all cannot-compare errors.
throw new ClassCastException(
String.format(
"cannot compare self-referential or overly nested data structures %s and %s",
Starlark.reprForErrors(x), Starlark.reprForErrors(y)));
}
}
} else {
// different types
if (x instanceof StarlarkFloat && y instanceof StarlarkInt) {
// float < int
double xf = ((StarlarkFloat) x).toDouble();
return Double.isNaN(xf) ? +1 : -StarlarkInt.compareIntAndDouble((StarlarkInt) y, xf);
} else if (x instanceof StarlarkInt && y instanceof StarlarkFloat) {
// int < float
double yf = ((StarlarkFloat) y).toDouble();
return Double.isNaN(yf) ? -1 : StarlarkInt.compareIntAndDouble((StarlarkInt) x, yf);
}View on GitHub (pinned to e6e199d060)
Solutions
- Compare by a derived scalar key instead of the whole structure: sorted(nodes, key=lambda n: n.id).
- Break cycles: never insert a container into itself; store indices/labels instead of direct references.
- If cycles are required, compare along an explicit field path rather than recursively.
Example fix
# before
x = []
x.append(x)
sorted([x, []]) # recursive compare -> stack overflow
# after
x = []
x.append("self")
sorted([x, []], key=len) Defensive patterns
Strategy: validation
Validate before calling
# never compare containers that may be cyclic; compare a derived key key = lambda n: n.id # scalar key, safe under recursion m = max(nodes, key=key)
Prevention
- Store labels/indices instead of direct container references in structures you will sort.
- Always sort complex values with an explicit scalar key=, never on the raw value.
- Assert acyclicity when constructing nested data.
When it happens
Trigger: x = []; x.append(x); x < x, comparing two mutually-referencing lists, or sorting a list whose elements are deeply nested structures (thousands of levels) with < or sorted().
Common situations: Building cyclic configuration graphs in Starlark (node lists containing node lists) and then sorting or min/max-ing them; deep AST-like data compared directly instead of by a structural key.
Related errors
- unsupported comparison: %s <=> %s
- unsupported comparison: %s <=> %s
- unsupported comparison: %s <=> %s
- This converter doesn't support Starlark reversal.
- Invalid options syntax: %s Note: Negative target patterns ca
AI-assisted analysis of bazelbuild/bazel@e6e199d060 (2026-08-14).
Data as JSON: /api/errors/1de828679ec1b065.
Report an issue: GitHub.