oracle/graal · error · LoadingConstraintViolationException

New loading constraint violates an older one!

Error message

New loading constraint violates an older one!

What it means

While merging/registering loading constraints, LoadingConstraintsShared.checkConstraint detects that an existing constraint for a type symbol is already bound to a loaded class (c1.klass) and the new constraint names a different loaded class. Because both classes exist and differ, the new constraint contradicts the recorded one and LoadingConstraintViolationException is thrown.

Source

Thrown at espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/constraints/LoadingConstraintsShared.java:254

                if (!exists(c1.klass)) {
                    c1.klass = klass;
                }
            } else {
                mergeConstraints(bucket, c1, c2);
            }
        }
    }

    private ConstraintBucket<Loader, Storage> lookup(Symbol<Type> type) {
        return pairings.get(type);
    }

    private long checkConstraint(long klass, Constraint<Loader, Storage> c1) throws LoadingConstraintViolationException {
        if (c1 != null) {
            if (exists(c1.klass)) {
                if (exists(klass)) {
                    if (klass != c1.klass) {
                        throw new LoadingConstraintViolationException("New loading constraint violates an older one!");
                    }
                } else {
                    return c1.klass;
                }
            } else {
                c1.klass = klass;
            }
        }
        return klass;
    }

    private void mergeConstraints(ConstraintBucket<Loader, Storage> bucket, Constraint<Loader, Storage> c1, Constraint<Loader, Storage> c2) {
        assert Thread.holdsLock(bucket);
        Constraint<Loader, Storage> merge;
        Constraint<Loader, Storage> delete;
        if (c1.loaders.length < c2.loaders.length) {
            merge = c2;
            delete = c1;

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Ensure the type named in the failing constraint is loaded by a single common loader (or a common parent) across all loaders involved.
  2. Undeploy/drop the loader holding the stale class so the old constraint's class can be garbage-collected before reloading.
  3. Audit for duplicate jars/classes across deployment units and remove the duplicates.
  4. Wrap the triggering call in a catch of the resulting LinkageError and report which loader pair conflicted.
Defensive patterns

Strategy: try-catch

Try / catch

try {
    reloadedOperation();
} catch (LinkageError e) {
    if (e.getMessage() != null && e.getMessage().contains("violates an older one")) {
        // old constraint still bound to a stale class: force context restart
        scheduleContextRestart();
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: A second cross-loader operation reuses a Symbol<Type> whose constraint bucket already resolved to class A, while the new call site resolves the same name to class B (both loaded). Typical with several loaders resolving constrained method signatures inconsistently.

Common situations: Partial redeployment where one loader keeps the old class and a new loader loads an incompatible new version; duplicated classes across sibling loaders that later interact through constrained method calls.

Related errors


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