microsoft/semantic-kernel · error · PluginInitializationError

Duplicate operationId: '{operationId}', path: '{path}', meth

Error message

Duplicate operationId: '{operationId}', path: '{path}', method: '{method}'

What it means

The parser tracks every `operationId` it registers in `unique_operation_ids_registered`; if the same id appears twice it raises `PluginInitializationError` naming the id, path, and method. `operationId` doubles as the kernel function name, so duplicates would collide.

Source

Thrown at python/semantic_kernel/connectors/openapi_plugin/openapi_parser.py:260

                server_entry = {
                    "url": server.get("url", "/"),
                    "variables": server.get("variables", {}),
                    "description": server.get("description", ""),
                }
                server_urls.append(server_entry)
        else:
            # Default server if none specified
            server_urls = [{"url": "/", "variables": {}, "description": ""}]

        for path, methods in paths.items():
            for method, details in methods.items():
                request_method = method.lower()
                # Validate that operationId exists
                if "operationId" not in details:
                    raise PluginInitializationError(f"operationId missing, path: '{path}', method: '{method}'")
                operationId = details["operationId"]
                if operationId in unique_operation_ids_registered:
                    raise PluginInitializationError(
                        f"Duplicate operationId: '{operationId}', path: '{path}', method: '{method}'"
                    )
                unique_operation_ids_registered.add(operationId)

                summary = details.get("summary", None)
                description = details.get("description", None)

                # Exclude operations whose path would resolve to a different effective request target
                # than the one offered to the selection predicate: a dot-segment (encoded or literal)
                # or a non-relative (absolute / authority-changing) path. Excluding them here keeps
                # operation selection and request construction on one canonical target so such a path
                # cannot bypass an include/exclude operation-selection filter.
                if RestApiOperation._contains_dot_segment(path) or RestApiOperation._is_non_relative_path(path):
                    logger.warning(
                        f"Skipping operation {operationId} at path '{path}' because it does not resolve to a "
                        f"relative path on the configured server."
                    )
                    continue

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Rename one of the duplicate `operationId`s to make it unique.
  2. Use a linter (Spectral `operation-operationId-unique`) to find all collisions.
  3. If merging specs, run a dedup pass that namespaces ids (e.g. prefix with the tag).
  4. Pre-process the spec to auto-disambiguate duplicates as `{operationId}_{method}_{path}`.

Example fix

# before
paths:
  /pets:
    get: { operationId: list, ... }
  /owners:
    get: { operationId: list, ... }   # raises 1495

# after
paths:
  /pets:
    get: { operationId: listPets, ... }
  /owners:
    get: { operationId: listOwners, ... }
Defensive patterns

Strategy: validation

Validate before calling

from collections import Counter

def duplicate_operation_ids(spec) -> list[str]:
    ids = []
    for path, methods in spec.get("paths", {}).items():
        for method, d in methods.items():
            oid = (d or {}).get("operationId")
            if oid:
                ids.append(oid)
    return [oid for oid, n in Counter(ids).items() if n > 1]

dupes = duplicate_operation_ids(spec)
assert not dupes, dupes

Type guard

def operation_ids_are_unique(spec) -> bool:
    return not duplicate_operation_ids(spec)

Try / catch

from semantic_kernel.exceptions import PluginInitializationError

try:
    kernel.add_openapi_plugin(plugin_name="x", openapi_parsed_spec=spec)
except PluginInitializationError as e:
    if "Duplicate operationId" in str(e):
        # disambiguate ids, then retry
        raise
    raise

Prevention

When it happens

Trigger: Two operations (different path/method, or aliased) sharing the same `operationId` string. Also possible after spec deduplication/merging that left duplicate ids.

Common situations: Copy-pasted operations; specs merged from multiple teams; aliases for the same endpoint; tools that auto-generate ids by method only (so `GET /a` and `GET /b` collide).

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/e3241160a17362b1. Report an issue: GitHub.