OpenAPITools/openapi-generator · error · RuntimeException
Malformed OpenAPI version '%s' in a source spec. Expected ex
Error message
Malformed OpenAPI version '%s' in a source spec. Expected exactly three numeric components (MAJOR.MINOR.PATCH) without leading zeroes, such as '3.0.3' or '3.1.0'.
What it means
Before comparing versions, resolveOutputVersion() runs every declared `openapi` value through isWellFormedVersion(), which demands exactly three numeric components (MAJOR.MINOR.PATCH) with no leading zeroes — e.g. '3.0.3' or '3.1.0'. This blocks malformed values like '3.x.3', '3.0', or '3.01.0' from sneaking through a lenient numeric parse that would normalize junk segments to zero. The malformed value is echoed in the message.
Source
Thrown at modules/openapi-generator/src/main/java/org/openapitools/codegen/config/MergedSpecBuilder.java:536
.map(OpenAPI::getOpenapi)
.collect(Collectors.toList());
if (versions.stream().noneMatch(Objects::nonNull)) {
// Every source is unversioned — fall back to the default.
return "3.0.3";
}
// At least one source declares a version. Since 'openapi' is required, an unversioned
// source cannot be assumed compatible and must not be silently accepted.
if (versions.stream().anyMatch(Objects::isNull)) {
throw new RuntimeException(
"Cannot merge specs where some declare an OpenAPI version and others do not. The 'openapi' "
+ "field is required; every source spec must declare a version so compatibility can be verified.");
}
// Reject malformed versions before comparing, so a value like '3.x.3' cannot pass the
// major.minor check by having its non-numeric segment normalized to zero.
for (String version : versions) {
if (!isWellFormedVersion(version)) {
throw new RuntimeException(String.format(Locale.ROOT,
"Malformed OpenAPI version '%s' in a source spec. Expected exactly three numeric "
+ "components (MAJOR.MINOR.PATCH) without leading zeroes, such as '3.0.3' or '3.1.0'.",
version));
}
}
String firstMajorMinor = majorMinor(versions.get(0));
for (String version : versions) {
if (!majorMinor(version).equals(firstMajorMinor)) {
throw new RuntimeException(String.format(Locale.ROOT,
"Cannot merge specs that declare incompatible OpenAPI versions %s. All specs must share "
+ "the same major.minor version (e.g. all 3.0.x or all 3.1.x); mixing 3.0 and 3.1 "
+ "is not supported because version-specific fields and semantics are not translated.",
versions.stream().distinct().collect(Collectors.toList())));
}
}
// Same major.minor across all specs — declare the highest patch version encountered.
String highest = versions.get(0);
for (String version : versions) {View on GitHub (pinned to fcec517be3)
Solutions
- Set the version in the flagged spec to a strict MAJOR.MINOR.PATCH form matching the other sources (e.g. 3.0.3).
- Remove leading zeroes from any segment (3.01.0 → 3.1.0).
- Add a CI lint (regex ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$) over all specs entering the merge.
Example fix
# before openapi: 3.1 # after openapi: 3.1.0
Defensive patterns
Strategy: validation
Validate before calling
private static final Pattern OAS_VERSION = Pattern.compile("^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$");
for (String f : specFiles) {
String v = readOpenapiField(f);
if (v != null && !OAS_VERSION.matcher(v).matches()) {
throw new IllegalArgumentException(f + ": malformed openapi version " + v);
}
} Try / catch
Catch RuntimeException containing "Malformed OpenAPI version"; echo the file + version and block the merge until fixed (deterministic config error).
Prevention
- Enforce the MAJOR.MINOR.PATCH regex in editor/CI lint for the openapi field.
- Never leave placeholder versions like 3.x in committed specs.
When it happens
Trigger: A source spec with `openapi: 3` or `openapi: 3.1`; a value like `openapi: 3.x.3` from hand-editing; leading-zero forms like `openapi: 3.0.01`.
Common situations: Hand-written partial specs where the version was abbreviated; templating that injects a placeholder into the version; tools emitting non-standard version strings; copy/paste from docs showing '3.x' wildcards.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- inputSpecFiles list is empty — nothing to merge
- %s Input: `%s`. Error: %s
- filter with no value not supported :[{filter}]
- Couldn't load template engine adapter %s. Available options:
- Spec directory doesn't contain any specification
AI-assisted analysis of OpenAPITools/openapi-generator@fcec517be3 (2026-08-22).
Data as JSON: /api/errors/fedf9a00f6f3e577.
Report an issue: GitHub.