junit-team/junit5 · error · JUnitException

Chain of InvocationInterceptors never called invocation

Error message

Chain of InvocationInterceptors never called invocation: %s

What it means

Internal assertion inside ValidatingInvocation: after running the entire InvocationInterceptor chain for an intercepted call (constructor/method/lifecycle), invokedOrSkipped was never set, meaning no interceptor ever called Invocation.proceed() or Invocation.skip(). The message lists every interceptor in the chain so you can see which one swallowed the call.

Solutions

  1. Identify the listed interceptor that owns the missing proceed() call.
  2. Ensure the interceptor always either calls invocation.proceed() (to continue) or invocation.skip() (to halt) on every code path.
  3. If the interceptor intentionally replaces the invocation, call proceed() against the wrapped chain or invoke the underlying target directly and return its value - but never silently drop.

Example fix

// before
@Override
public <T> T interceptTestClassConstructor(Invocation<T> inv, ReflectiveInvocationContext<T> ctx, ExtensionContext ec) {
    log("creating");
    return null; // forgot proceed()
}
// after
@Override
public <T> T interceptTestClassConstructor(Invocation<T> inv, ReflectiveInvocationContext<T> ctx, ExtensionContext ec) throws Throwable {
    log("creating");
    return inv.proceed();
}
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: An InvocationInterceptor.intercept* method returns without ever calling invocation.proceed() or invocation.skip(); verifyInvokedAtLeastOnce() then fires at the end of InvocationInterceptorChain.invoke. The throw site is at line 142-143 / fail() at 149.

Common situations: A third-party or custom InvocationInterceptor short-circuits execution intentionally but forgets to either proceed or skip; an interceptor swallows the Invocation and substitutes its own logic without delegating; an interceptor throws but the throw is caught upstream leaving the chain un-proceeded (rare).

Related errors


AI-assisted analysis of junit-team/junit5@f070c699a0 (2026-08-11). Data as JSON: /api/errors/21eed077f733a05e. Report an issue: GitHub.

Appendix: source

Thrown at junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/InvocationInterceptorChain.java:149

			delegate.skip();
		}

		private void markInvokedOrSkipped() {
			if (!invokedOrSkipped.compareAndSet(false, true)) {
				fail("Chain of InvocationInterceptors called invocation multiple times instead of just once");
			}
		}

		void verifyInvokedAtLeastOnce() {
			if (!invokedOrSkipped.get()) {
				fail("Chain of InvocationInterceptors never called invocation");
			}
		}

		private void fail(String prefix) {
			String commaSeparatedInterceptorClasses = interceptors.stream().map(Object::getClass).map(
				Class::getName).collect(joining(", "));
			throw new JUnitException(prefix + ": " + commaSeparatedInterceptorClasses);
		}
	}

}

View on GitHub (pinned to f070c699a0)