{"record":{"id":"7cfdf7307066868b","repo":"bazelbuild/bazel","slug":"unsupported-comparison-s-s-7cfdf7","errorCode":null,"errorMessage":"unsupported comparison: %s <=> %s","messagePattern":"unsupported comparison: (.+?) <=> (.+?)","errorType":"exception","errorClass":"EvalException","httpStatus":null,"severity":"error","filePath":"src/main/java/net/starlark/java/eval/MethodLibrary.java","lineNumber":139,"sourceCode":"    try {\n      EvalUtils.addIterator(items); // to prevent keyFn from mutating items\n      if (keyFn.isPresent()) {\n        try {\n          return stream(items)\n              .map(value -> ValueWithComparisonKey.make(value, keyFn.get(), thread))\n              .max(comparing(ValueWithComparisonKey::getComparisonKey, maxOrdering))\n              .get()\n              .getValue();\n        } catch (ValueWithComparisonKey.KeyCallException ex) {\n          Throwables.throwIfInstanceOf(ex.getCause(), EvalException.class);\n          Throwables.throwIfInstanceOf(ex.getCause(), InterruptedException.class);\n          throw new AssertionError(\"Got invalid ValueWithComparisonKey.KeyCallException\", ex);\n        }\n      } else {\n        return maxOrdering.max(items);\n      }\n    } catch (ClassCastException ex) {\n      throw new EvalException(ex.getMessage()); // e.g. unsupported comparison: int <=> string\n    } catch (NoSuchElementException ex) {\n      throw new EvalException(\"expected at least one item\", ex);\n    } finally {\n      EvalUtils.removeIterator(items);\n    }\n  }\n\n  /**\n   * Original value decorated with its comparison key; storing the comparison key alongside the\n   * value ensures that we call the comparison key computation function only once per original value\n   * (which is important in case the function has side effects).\n   */\n  private static final class ValueWithComparisonKey {\n    private final Object value;\n    private final Object comparisonKey;\n\n    private ValueWithComparisonKey(Object value, Object comparisonKey) {\n      this.value = value;","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/bazelbuild/bazel/blob/e6e199d0601a244511b4cf18c8b2828aa73db1fd/src/main/java/net/starlark/java/eval/MethodLibrary.java#L121-L157","documentation":"Thrown by the built-in min()/max() when the elements being ranked are mutually incomparable. The ordering used by maxOrdering.max(items) (or by the comparison-key comparator when key= is given) throws ClassCastException, which MethodLibrary catches and converts to EvalException with the message 'unsupported comparison: T1 <=> T2'.","triggerScenarios":"max([1, \"a\", 2]), min((None, 1)), or max(items, key=lambda x: x.attr) where the key function returns mixed types for different elements (e.g. int for one element, string for another).","commonSituations":"Computing a max over user-supplied or file-derived data whose types are not guaranteed uniform; a key= function that returns None or an empty string as a sentinel for some elements; aggregating over a list built by concatenating heterogeneous sources.","solutions":["Normalize elements (or key results) to one type before calling min/max: max(items, key=lambda x: int(x)).","Make the key= function total: map None/missing sentinels to a sortable fallback such as float(\"-inf\") or \"\".","Pre-filter or pre-validate the list so all elements share a type.","Catch EvalException around the min()/max() call and degrade gracefully."],"exampleFix":"# before\nm = max(vals, key=lambda v: v.score)  # score is None for some items\n\n# after\nm = max(vals, key=lambda v: v.score if v.score != None else float(\"-inf\"))","handlingStrategy":"validation","validationCode":"# ensure key function yields one uniform type before min/max\nkeys = [k(v) for v in items]\nif len({type(k) for k in keys}) > 1:\n    fail(\"min/max over mixed key types\")\nm = max(items, key=k)","typeGuard":"def uniform_types(items):\n    t = type(items[0]) if items else None\n    return t != None and all(type(i) == t for i in items)","tryCatchPattern":null,"preventionTips":["Make key= functions total: never return None or mixed types.","Validate list homogeneity once at the boundary where the list is built.","Unit-test min/max on empty and heterogeneous fixtures."],"tags":["starlark","min-max","comparison","key-function","type-mismatch"],"backgroundTag":null,"analyzedSha":"e6e199d0601a244511b4cf18c8b2828aa73db1fd","analyzedAt":"2026-08-14T10:24:27.848Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}