junit-team/junit5 · critical · JUnitException
Third-party TestEngine '%s' is forbidden to use the reserved
Error message
Third-party TestEngine '%s' is forbidden to use the reserved '%s' TestEngine ID.
What it means
Thrown by EngineIdValidator.validateWellKnownClassName() when a TestEngine whose class is NOT one of JUnit's well-known implementations claims a reserved engine ID ('junit-jupiter', 'junit-vintage', or 'junit-platform-suite'). This guards against third-party engines impersonating official engines (issue #1557). The exception names the offending class and the reserved ID.
Source
Thrown at junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineIdValidator.java:82
}
private static @Nullable String wellKnownClassNameForEngineId(TestEngine testEngine) {
String engineId = Preconditions.notBlank(testEngine.getId(),
() -> "ID for TestEngine [%s] must not be null or blank".formatted(testEngine.getClass().getName()));
return switch (engineId) {
case "junit-jupiter" -> "org.junit.jupiter.engine.JupiterTestEngine";
case "junit-vintage" -> "org.junit.vintage.engine.VintageTestEngine";
case "junit-platform-suite" -> "org.junit.platform.suite.engine.SuiteTestEngine";
default -> null;
};
}
private static void validateWellKnownClassName(TestEngine testEngine, String expectedClassName) {
String actualClassName = testEngine.getClass().getName();
if (actualClassName.equals(expectedClassName)) {
return;
}
throw new JUnitException(
"Third-party TestEngine '%s' is forbidden to use the reserved '%s' TestEngine ID.".formatted(
actualClassName, testEngine.getId()));
}
}
View on GitHub (pinned to 956246301e)
Solutions
- Give your custom TestEngine a unique, non-reserved ID (do not start with 'junit-' and do not reuse official IDs).
- If you relocated the official engine via shading, also relocate its class so the well-known class name still matches, or change the ID.
- Remove the offending custom TestEngine from the ServiceLoader registrations.
Example fix
// before
public class MyEngine implements TestEngine {
public String getId() { return "junit-jupiter"; } // forbidden
}
// after
public class MyEngine implements TestEngine {
public String getId() { return "my-company-engine"; }
} Defensive patterns
Strategy: validation
Validate before calling
import org.junit.platform.engine.TestEngine;
Set<String> RESERVED = Set.of("junit-jupiter","junit-vintage","junit-platform-suite");
for (var eng : ServiceLoader.load(TestEngine.class)) {
if (RESERVED.contains(eng.getId()) && !isWellKnown(eng)) {
throw new IllegalStateException("Custom engine must not use reserved id: " + eng.getId());
}
} Type guard
static boolean usesReservedId(TestEngine e) {
return e.getId().startsWith("junit-") || Set.of(
"junit-jupiter","junit-vintage","junit-platform-suite").contains(e.getId());
} Prevention
- Never reuse official engine IDs in custom TestEngine implementations.
- If you relocate/shade the official engine, keep its class name intact or change the ID.
- Audit ServiceLoader registrations for engines claiming junit-* IDs.
When it happens
Trigger: A custom TestEngine whose getId() returns 'junit-jupiter' but whose class is not org.junit.jupiter.engine.JupiterTestEngine (similarly for vintage/suite). Triggered at Launcher creation via EngineIdValidator.validate().
Common situations: Writing a custom/forked engine and reusing an official ID. Bytecode relocation/shading that moves JupiterTestEngine to a new package but keeps getId()='junit-jupiter'. A malicious or mistaken ServiceLoader provider impersonating an official engine.
Related errors
- Cannot override the standard style 'NONE'
- Could not read color palette properties
- Could not open color palette properties file
- Failed to transform configuration parameter with key '%s' an
- Failed to create ForkJoinPool
AI-assisted analysis of junit-team/junit5@956246301e (2026-08-04).
Data as JSON: /data/errors/32c794f2108becda.json.
Report an issue: GitHub.