OpenAPITools/openapi-generator · error · RuntimeException

Path+method conflict during spec merge: %s %s is defined in

Error message

Path+method conflict during spec merge: %s %s is defined in multiple specs. Unlike schema reuse, duplicate HTTP methods on the same path are not valid — check that your spec files do not overlap. Keeping the first definition.

What it means

MergedSpecBuilder.mergePathItem throws this when the same path + HTTP method is defined in more than one input spec and mergeConflictStrategy is FAIL. Unlike schemas, two operations on the same method+path cannot coexist in a valid OpenAPI document, so only one can survive — the merge keeps the first definition and aborts under FAIL.

Source

Thrown at modules/openapi-generator/src/main/java/org/openapitools/codegen/config/MergedSpecBuilder.java:716

     *       otherwise name+in); first wins on conflict</li>
     *   <li>Servers: added if not already present by URL</li>
     *   <li>Extensions: added if not already present by key</li>
     *   <li>Summary and description: always kept from the first ({@code existing}) PathItem</li>
     * </ul>
     */
    private void mergePathItem(PathItem existing, PathItem incoming, String pathKey) {
        if (incoming.readOperationsMap() == null) {
            return;
        }
        incoming.readOperationsMap().forEach((method, operation) -> {
            if (existing.readOperationsMap() != null && existing.readOperationsMap().containsKey(method)) {
                String message = String.format(Locale.ROOT,
                        "Path+method conflict during spec merge: %s %s is defined in multiple specs. " +
                        "Unlike schema reuse, duplicate HTTP methods on the same path are not valid — " +
                        "check that your spec files do not overlap. Keeping the first definition.",
                        method, pathKey);
                if (conflictStrategy == MergeConflictStrategy.FAIL) {
                    throw new RuntimeException(message);
                }
                LOGGER.warn(message);
                // WARN: keep the first (existing) operation, skip the incoming one.
                return;
            }
            existing.operation(method, operation);
        });

        // Merge path-level parameters (first wins on conflict). Identity is the $ref value when the
        // parameter is a reference; otherwise name+in. Without this, multiple distinct $ref
        // parameters would all collapse to the key "null:null" and all but the first would be lost.
        if (incoming.getParameters() != null) {
            List<Parameter> merged = existing.getParameters() != null
                    ? new ArrayList<>(existing.getParameters()) : new ArrayList<>();
            Set<String> existingKeys = merged.stream()
                    .map(MergedSpecBuilder::parameterIdentity)
                    .collect(Collectors.toSet());
            for (Parameter p : incoming.getParameters()) {

View on GitHub (pinned to fcec517be3)

Solutions

  1. De-duplicate: keep the path+method definition in exactly one spec file.
  2. If the endpoints are genuinely different, rename the path in one spec (e.g. /store/users vs /users).
  3. Remove the overlapping file from the merge input, or accept first-wins behavior by using the default WARN strategy instead of FAIL.

Example fix

# specs/a.yaml and specs/b.yaml (before) — both define:
paths:
  /users:
    get: ...
# after — only specs/a.yaml defines /users; specs/b.yaml drops it
# or rename in b.yaml:
paths:
  /store/users:
    get: ...
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: fail on duplicate path+method across spec files before merging
Set<String> seen = new HashSet<>();
for (String file : specFiles) {
    OpenAPI api = new OpenAPIV3Parser().read(file);
    api.getPaths().forEach((path, item) ->
        item.readOperationsMap().forEach((method, op) -> {
            if (!seen.add(method + " " + path))
                throw new IllegalStateException(method + " " + path + " defined again in " + file);
        }));
}

Try / catch

try {
    mergedSpec = mergedSpecBuilder.build();
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Path+method conflict during spec merge")) {
        // message names the method and path; keep the intended definition and delete the other
        throw new BuildException("Spec merge conflict: " + e.getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Directory merge where both spec files define 'get: /users'. When merging the second file, existing.readOperationsMap().containsKey(method) is true, and with FAIL the RuntimeException is thrown; with the default WARN the first definition is kept and the incoming one skipped.

Common situations: Two teams' specs that both expose /health or /status; a shared/common.yaml left in the merge directory alongside a spec that repeats the same endpoints; versioned specs (v1.yaml, v2.yaml) accidentally merged together.

Related errors


AI-assisted analysis of OpenAPITools/openapi-generator@fcec517be3 (2026-08-22). Data as JSON: /api/errors/bcec907519e4deda. Report an issue: GitHub.