OpenAPITools/openapi-generator · error · RuntimeException

operationId conflict during spec merge: '%s' (%s %s) is alre

Error message

operationId conflict during spec merge: '%s' (%s %s) is already used by another operation.

What it means

MergedSpecBuilder throws this when two operations across the OpenAPI spec files being merged share the same operationId and mergeConflictStrategy is FAIL. operationIds must be unique in a merged document because they become generated client method names. With the default WARN strategy the duplicate is instead renamed to '<id>_2' and only a warning is logged.

Source

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

        }
        Set<String> usedOperationIds = new HashSet<>();
        for (Map.Entry<String, PathItem> pathEntry : merged.getPaths().entrySet()) {
            PathItem pathItem = pathEntry.getValue();
            if (pathItem == null || pathItem.readOperationsMap() == null) {
                continue;
            }
            for (Map.Entry<PathItem.HttpMethod, Operation> opEntry : pathItem.readOperationsMap().entrySet()) {
                Operation operation = opEntry.getValue();
                String operationId = operation.getOperationId();
                if (operationId == null || operationId.isEmpty()) {
                    continue;
                }
                if (!usedOperationIds.add(operationId)) {
                    String message = String.format(Locale.ROOT,
                            "operationId conflict during spec merge: '%s' (%s %s) is already used by another operation.",
                            operationId, opEntry.getKey(), pathEntry.getKey());
                    if (conflictStrategy == MergeConflictStrategy.FAIL) {
                        throw new RuntimeException(message);
                    }
                    String uniqueId = operationId;
                    int suffix = 2;
                    while (!usedOperationIds.add(uniqueId + "_" + suffix)) {
                        suffix++;
                    }
                    uniqueId = uniqueId + "_" + suffix;
                    LOGGER.warn("{} Renaming to '{}'.", message, uniqueId);
                    operation.setOperationId(uniqueId);
                }
            }
        }
    }

    /**
     * Pushes a spec's root-level security requirements down onto each of its operations that does
     * not already declare operation-level security. In OpenAPI, root-level {@code security} applies
     * to every operation unless overridden; an explicit empty list on an operation disables security.

View on GitHub (pinned to fcec517be3)

Solutions

  1. Make the operationId unique across all merged files by prefixing it with its domain, e.g. store_getUser vs pet_getUser.
  2. Re-run with the default WARN conflict strategy so the duplicate is auto-renamed to <id>_2 (acceptable when collisions are benign).
  3. Exclude the overlapping spec file from the merge input directory or list if it was included by accident.

Example fix

# specs/store.yaml + specs/pet.yaml (before) — both files:
operationId: getUser
# after — specs/store.yaml:
operationId: store_getUser
# after — specs/pet.yaml:
operationId: pet_getUser
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: fail on duplicate operationIds across spec files before merging
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.parser.v3.OpenAPIV3Parser;
import java.util.*;

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) -> {
            String id = op.getOperationId();
            if (id != null && !seen.add(id))
                throw new IllegalStateException("Duplicate operationId '" + id + "' in " + file);
        }));
}

Try / catch

try {
    mergedSpec = mergedSpecBuilder.build();
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("operationId conflict during spec merge")) {
        // extract the operationId from the message, report owning spec, fix at source
        throw new BuildException("Spec merge conflict: " + e.getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Running openapi-generator in directory merge mode (inputSpec is a directory of .yaml/.yml/.json specs) with conflictStrategy=FAIL, where e.g. both petstore.yaml and store.yaml contain operationId 'getUser'. The second usedOperationIds.add(operationId) returns false and the RuntimeException aborts the merge.

Common situations: Microservice specs that each define generic CRUD names like 'list' or 'getById'; copying an existing spec as a template and forgetting to rename operationIds; enabling the strict FAIL strategy in CI to surface overlaps between team-owned spec files.

Related errors


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