oracle/graal · error · TypeError

Cannot compare {JavaLangRuntimeVersion.__name__} to {type(ot

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.

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)

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.