{"record":{"id":"07124f293531d914","repo":"OpenAPITools/openapi-generator","slug":"cannot-merge-specs-that-declare-incompatible-opena","errorCode":null,"errorMessage":"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.","messagePattern":"Cannot merge specs that declare incompatible OpenAPI versions (.+?)\\. 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\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"modules/openapi-generator/src/main/java/org/openapitools/codegen/config/MergedSpecBuilder.java","lineNumber":545,"sourceCode":"        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) {\n            if (compareVersions(version, highest) > 0) {\n                highest = version;\n            }\n        }\n        return highest;\n    }\n\n    /**\n     * Returns {@code true} if {@code version} is a well-formed OpenAPI version: exactly three ASCII","sourceCodeStart":527,"sourceCodeEnd":563,"githubUrl":"https://github.com/OpenAPITools/openapi-generator/blob/fcec517be3cf5b7964296bcba25fbc97541484e7/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/MergedSpecBuilder.java#L527-L563","documentation":"After well-formedness checks, resolveOutputVersion() compares every source's major.minor against the first spec's; any divergence throws with the distinct version list. Merging across major.minor lines (3.0.x with 3.1.x) is unsupported because version-specific fields and semantics are not translated. The merged output declares the highest patch version among sources once this check passes.","triggerScenarios":"Merging pet.yaml (openapi: 3.0.1) with store.yaml (openapi: 3.1.0); introducing a newly-authored 3.1 spec (for e.g. nullable/examples changes) into an existing 3.0 catalog.","commonSituations":"Gradual 3.0→3.1 migrations where some teams converted early; mixed tooling emitting different default versions; pulling third-party specs with a different baseline into an internal merge.","solutions":["Upgrade or downgrade all source specs to one major.minor line (convert 3.0 specs to 3.1, or the reverse) before merging.","If a spec only differs in patch (3.0.1 vs 3.0.3), align them anyway for clean output — though patches already merge to the highest.","Split the merge into two runs, one per version line, if migration must be staged.","Use a converter (e.g. swagger-converter / openapi-diff tooling) to bring stragglers onto the chosen line."],"exampleFix":"# before\npet.yaml:    openapi: 3.0.1\nstore.yaml:  openapi: 3.1.0\n# after (align all to one line)\npet.yaml:    openapi: 3.1.0\nstore.yaml:  openapi: 3.1.0","handlingStrategy":"validation","validationCode":"// All specs must share one major.minor before merging\nSet<String> majorMinor = specFiles.stream()\n        .map(f -> readOpenapiField(f))\n        .filter(Objects::nonNull)\n        .map(v -> v.substring(0, v.lastIndexOf('.')))\n        .collect(Collectors.toSet());\nif (majorMinor.size() > 1) throw new IllegalArgumentException(\"Mixed versions: \" + majorMinor);","typeGuard":null,"tryCatchPattern":"Catch RuntimeException containing \"incompatible OpenAPI versions\"; print the distinct version set, then route specs into per-version merge runs or convert them.","preventionTips":["Standardize one OpenAPI line (e.g. all 3.0.x) in your spec repository guidelines.","Gate merges on a version-homogeneity check in CI.","When starting a 3.1 migration, convert the whole catalog in one commit rather than gradually."],"tags":["openapi","spec-merge","version-mismatch","migration"],"backgroundTag":"spec-version-mismatch","analyzedSha":"fcec517be3cf5b7964296bcba25fbc97541484e7","analyzedAt":"2026-08-22T11:13:11.613Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}