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.

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.

Appendix: 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)