oracle/graal · error · TypeError

Cannot compare to

Error message

Cannot compare {JavaLangRuntimeVersion.__name__} to {type(other).__name__}

What it means

Thrown by Version.create(int...) when any component of the version string, after trailing zeros are trimmed, is less than zero. The factory validates that a version is built from at least one non-zero, non-negative integer component before constructing the immutable Version. It is an IllegalArgumentException, so it signals caller misuse of the varargs API rather than an environment problem.

Solutions

  1. Validate all components are >= 0 (and at least one > 0) before calling Version.create.
  2. If the value comes from a string, parse with a strict pattern such as \d+(\.\d+)* so negatives can never reach the API.
  3. Clamp or reject negative computed components at the source (the calculation that produced them) instead of catching the exception.

Example fix

// before
Version v = Version.create(major, minor - 1, patch);

// after
if (minor - 1 < 0) {
    throw new IllegalArgumentException("minor version would go negative: " + minor);
}
Version v = Version.create(major, minor - 1, patch);
Defensive patterns

Strategy: validation

Validate before calling

static boolean isValidVersion(int... parts) {
    boolean anyNonZero = false;
    for (int p : parts) {
        if (p < 0) return false;
        if (p != 0) anyNonZero = true;
    }
    return anyNonZero;
}

// before calling:
if (!isValidVersion(major, minor, patch)) throw new IllegalArgumentException("bad version parts");
Version.create(major, minor, patch);

Try / catch

try {
    Version v = Version.create(parts);
} catch (IllegalArgumentException e) {
    // surface as config-validation error to the user; do not retry
}

Prevention

When it happens

Trigger: Calling Version.create(-1, 0, 0), Version.create(19, -3), or passing an array containing a negative element (e.g. parsed from user input like "19.-3.0"). Note trailing zeros are trimmed first, so Version.create(0) fails earlier with 'At least one non-zero version must be specified.' instead.

Common situations: Parsing version numbers from CLI arguments, config files, or manifest data without sanitizing; arithmetic that computes a version component and can go negative (e.g. decrementing a minor version past 0); unit tests exercising malformed version input.

Related errors


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/fa0c25a4b831d91f. Report an issue: GitHub.

Appendix: source

Thrown at compiler/mx.compiler/mx_compiler.py:97

jdk = mx.get_jdk(tag='default')


class JavaLangRuntimeVersion(mx.Comparable):
    """Wrapper for java.lang.Runtime.Version"""

    _cmp_cache = {}
    _feature_re = re.compile('[1-9][0-9]*')

    def __init__(self, version, jdk=None):
        self.version = version
        self.jdk = jdk or mx.get_jdk()

    def __str__(self):
        return self.version

    def __cmp__(self, other):
        if not isinstance(other, JavaLangRuntimeVersion):
            raise TypeError(f'Cannot compare {JavaLangRuntimeVersion.__name__} to {type(other).__name__}')
        this_version = self.version
        other_version = other.version
        if this_version == other_version:
            return 0
        if self.feature() == 21 and other.feature() == 21:
            # JDK 21 uses the legacy version scheme where the jdkVersion is irrelevant (and imprecise).
            # Thus, we do not perform a full version check.
            return 0
        return JavaLangRuntimeVersion.compare(this_version, other_version, jdk)

    @staticmethod
    def compare(this_version, other_version, jdk):
        key = (this_version, other_version)
        cached = JavaLangRuntimeVersion._cmp_cache.get(key, None)
        if cached is not None:
            return cached
        source_path = join(_suite.dir, 'src', 'jdk.graal.compiler', 'src', 'jdk', 'graal', 'compiler',
                           'hotspot',

View on GitHub (pinned to a66e9ccd1d)