{"record":{"id":"fedf9a00f6f3e577","repo":"OpenAPITools/openapi-generator","slug":"malformed-openapi-version-s-in-a-source-spec-e","errorCode":null,"errorMessage":"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'.","messagePattern":"Malformed OpenAPI version '(.+?)' in a source spec\\. Expected exactly three numeric components \\(MAJOR\\.MINOR\\.PATCH\\) without leading zeroes, such as '3\\.0\\.3' or '3\\.1\\.0'\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"modules/openapi-generator/src/main/java/org/openapitools/codegen/config/MergedSpecBuilder.java","lineNumber":536,"sourceCode":"                .map(OpenAPI::getOpenapi)\n                .collect(Collectors.toList());\n\n        if (versions.stream().noneMatch(Objects::nonNull)) {\n            // Every source is unversioned — fall back to the default.\n            return \"3.0.3\";\n        }\n        // At least one source declares a version. Since 'openapi' is required, an unversioned\n        // source cannot be assumed compatible and must not be silently accepted.\n        if (versions.stream().anyMatch(Objects::isNull)) {\n            throw new RuntimeException(\n                    \"Cannot merge specs where some declare an OpenAPI version and others do not. The 'openapi' \"\n                            + \"field is required; every source spec must declare a version so compatibility can be verified.\");\n        }\n        // Reject malformed versions before comparing, so a value like '3.x.3' cannot pass the\n        // major.minor check by having its non-numeric segment normalized to zero.\n        for (String version : versions) {\n            if (!isWellFormedVersion(version)) {\n                throw new RuntimeException(String.format(Locale.ROOT,\n                        \"Malformed OpenAPI version '%s' in a source spec. Expected exactly three numeric \"\n                                + \"components (MAJOR.MINOR.PATCH) without leading zeroes, such as '3.0.3' or '3.1.0'.\",\n                        version));\n            }\n        }\n        String firstMajorMinor = majorMinor(versions.get(0));\n        for (String version : versions) {\n            if (!majorMinor(version).equals(firstMajorMinor)) {\n                throw new RuntimeException(String.format(Locale.ROOT,\n                        \"Cannot merge specs that declare incompatible OpenAPI versions %s. All specs must share \"\n                                + \"the same major.minor version (e.g. all 3.0.x or all 3.1.x); mixing 3.0 and 3.1 \"\n                                + \"is not supported because version-specific fields and semantics are not translated.\",\n                        versions.stream().distinct().collect(Collectors.toList())));\n            }\n        }\n        // Same major.minor across all specs — declare the highest patch version encountered.\n        String highest = versions.get(0);\n        for (String version : versions) {","sourceCodeStart":518,"sourceCodeEnd":554,"githubUrl":"https://github.com/OpenAPITools/openapi-generator/blob/fcec517be3cf5b7964296bcba25fbc97541484e7/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/MergedSpecBuilder.java#L518-L554","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","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."],"exampleFix":"# before\nopenapi: 3.1\n# after\nopenapi: 3.1.0","handlingStrategy":"validation","validationCode":"private static final Pattern OAS_VERSION = Pattern.compile(\"^(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)$\");\nfor (String f : specFiles) {\n    String v = readOpenapiField(f);\n    if (v != null && !OAS_VERSION.matcher(v).matches()) {\n        throw new IllegalArgumentException(f + \": malformed openapi version \" + v);\n    }\n}","typeGuard":null,"tryCatchPattern":"Catch RuntimeException containing \"Malformed OpenAPI version\"; echo the file + version and block the merge until fixed (deterministic config error).","preventionTips":["Enforce the MAJOR.MINOR.PATCH regex in editor/CI lint for the openapi field.","Never leave placeholder versions like 3.x in committed specs."],"tags":["openapi","spec-merge","version-validation","configuration"],"backgroundTag":"invalid-version-string","analyzedSha":"fcec517be3cf5b7964296bcba25fbc97541484e7","analyzedAt":"2026-08-22T11:13:11.613Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}