OpenAPITools/openapi-generator · error · RuntimeException
Failed to load custom NORMALIZER_CLASS '{className}'. This c
Error message
Failed to load custom NORMALIZER_CLASS '{className}'. This class must be visible on the generation runtime classpath (i.e. resolvable either by the current thread's context classloader or by the classloader that loaded openapi-generator itself). Ensure the class (and its dependencies) is on the classpath used to launch the generator. What it means
OpenAPINormalizer.createNormalizer handles the NORMALIZER_CLASS rule: instead of built-in rules it reflectively loads a user-supplied class via loadNormalizerClass (thread context classloader first, then openapi-generator's own loader - deliberately friendly to Gradle Worker API isolation). ClassNotFoundException is rethrown with this guidance: the class must be visible to the classloader of the RUNNING generator process, i.e. on the launch classpath, not merely on your project's compile classpath.
Source
Thrown at modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java:190
final String LOOSE_NULL_DEFINITIONS = "LOOSE_NULL_DEFINITIONS";
// ============= end of rules =============
private static final String ONE_OF_ANY_OF_ENUM_SIMPLIFIED = "Simplified {} with enum sub-schemas to single enum: {} since rule {} was enabled";
/**
* Factory constructor for OpenAPINormalizer.
*
* Default can be overriden by setting the NORMALIZER_CLASS rule
*/
public static OpenAPINormalizer createNormalizer(OpenAPI openAPI, Map<String, String> inputRules) {
if (inputRules.containsKey(NORMALIZER_CLASS)) {
String className = inputRules.get(NORMALIZER_CLASS);
Class<?> clazz;
try {
clazz = loadNormalizerClass(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException(
"Failed to load custom " + NORMALIZER_CLASS + " '" + className + "'. This class must be "
+ "visible on the generation runtime classpath (i.e. resolvable either by the "
+ "current thread's context classloader or by the classloader that loaded "
+ "openapi-generator itself). Ensure the class (and its dependencies) is on the "
+ "classpath used to launch the generator.", e);
}
try {
Constructor<?> constructor = clazz.getConstructor(OpenAPI.class, Map.class);
return (OpenAPINormalizer) constructor.newInstance(openAPI, inputRules);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(
"Failed to instantiate custom " + NORMALIZER_CLASS + " '" + className + "'. The class was "
+ "found but could not be constructed; it must declare a public constructor "
+ "accepting (OpenAPI, Map<String, String>) and that constructor must not throw.", e);
}
} else {
return new OpenAPINormalizer(openAPI, inputRules);
}View on GitHub (pinned to fcec517be3)
Solutions
- Fix the fully-qualified class name first: it must match package + class exactly (no spaces, correct casing).
- Get the class onto the GENERATOR's runtime classpath: with the Maven plugin, declare the normalizer artifact inside the plugin's <dependencies> block (not the project's); with the CLI, launch via java -cp 'your-normalizer.jar:openapi-generator-cli.jar' org.openapitools.codegen.OpenAPIGenerator or build an uber-jar including it.
- In embedded/Gradle contexts, set the thread context classloader (Thread.currentThread().setContextClassLoader(...)) to a loader that sees the class before invoking generation, matching what loadNormalizerClass prefers.
- Verify visibility at runtime before configuring: Class.forName(name, false, Thread.currentThread().getContextClassLoader()) in a smoke test.
Example fix
<!-- before: dependency only on the project, plugin can't see it -->
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
</plugin>
<!-- after: dependency inside the plugin block -->
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>my-normalizer</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</plugin> Defensive patterns
Strategy: validation
Validate before calling
// Verify the normalizer class is visible to the runtime BEFORE configuring it
String className = "com.example.MyNormalizer";
try {
Class.forName(className, false, Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException ctxMissing) {
try {
Class.forName(className, false, OpenAPINormalizer.class.getClassLoader());
} catch (ClassNotFoundException coreMissing) {
throw new IllegalStateException(
"NORMALIZER_CLASS not on generator runtime classpath: " + className);
}
}
Map<String, String> rules = Map.of("NORMALIZER_CLASS", className); Try / catch
try {
OpenAPINormalizer.createNormalizer(openAPI, rules);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Failed to load custom NORMALIZER_CLASS")) {
// classpath issue: add jar to plugin/CLI classpath; rethrow with remediation
throw new IllegalStateException("Add normalizer jar to the generator's classpath", e);
}
throw e;
} Prevention
- Declare custom-normalizer artifacts inside the openapi-generator-maven-plugin <dependencies> block.
- For CLI use, launch with java -cp including your normalizer jar rather than the bare downloaded CLI.
- Pin the normalizer's openapi-generator dependency to the running version.
When it happens
Trigger: Passing --openapi-normalizer NORMALIZER_CLASS=com.example.MyNormalizer where com.example.MyNormalizer is not on the runtime classpath: using the standalone openapi-generator-cli jar without your classes; Maven plugin without the normalizer artifact declared inside the PLUGIN's <dependencies>; Gradle setup where the worker action classloader cannot see the class; simple FQCN typo or stale package after a rename.
Common situations: Writing a first custom normalizer and testing via the downloaded CLI; adding the dependency to the project instead of the maven-plugin block; renaming packages and forgetting the option string; shaded jars built without the normalizer module.
Related errors
- Can't instantiate config class with name '{name}'. The class
- Failed to instantiate custom NORMALIZER_CLASS '{className}'.
- Unable to locate /java-helidon/common/Status.java to discove
- Could not process model '{name}'.Please make sure that your
- Could not generate model '{modelName}'
AI-assisted analysis of OpenAPITools/openapi-generator@fcec517be3 (2026-08-22).
Data as JSON: /api/errors/0e7f46ded2ecf9c0.
Report an issue: GitHub.