PrefectHQ/fastmcp · error · ValueError

Cannot add unversioned {type_name} {logical_name!r}: version

Error message

Cannot add unversioned {type_name} {logical_name!r}: versioned {type_name}s with this name already exist (e.g., version={existing.version!r}). Either version all components or none.

What it means

The mirror case of version-mixing: registering an unversioned component when versioned components of the same type and logical name already exist raises ValueError, because unversioned and versioned identities for the same name cannot coexist.

Source

Thrown at fastmcp_slim/fastmcp/server/providers/local_provider/local_provider.py:171

            if not isinstance(existing, comp_type):
                continue

            _, existing_name = self._get_component_identity(existing)
            if existing_name != logical_name:
                continue

            existing_versioned = existing.version is not None
            if is_versioned != existing_versioned:
                type_name = comp_type.__name__.lower()
                if is_versioned:
                    raise ValueError(
                        f"Cannot add versioned {type_name} {logical_name!r} "
                        f"(version={component.version!r}): an unversioned "
                        f"{type_name} with this name already exists. "
                        f"Either version all components or none."
                    )
                else:
                    raise ValueError(
                        f"Cannot add unversioned {type_name} {logical_name!r}: "
                        f"versioned {type_name}s with this name already exist "
                        f"(e.g., version={existing.version!r}). "
                        f"Either version all components or none."
                    )

    def _add_component(self, component: _C) -> _C:
        """Add a component to unified storage.

        Args:
            component: The component to add.

        Returns:
            The component that was added (or existing if on_duplicate="ignore").
        """
        existing = self._components.get(component.key)
        if existing:
            if self._on_duplicate == "error":

View on GitHub (pinned to 1f02114297)

Solutions

  1. Assign a version to the new component to match the existing scheme.
  2. Remove the versioned components if you intend to go back to unversioned.
  3. Rename the new component to avoid the logical-name collision.

Example fix

// before
mcp.add_tool(greet_v1, version='1')
mcp.add_tool(greet_simple)  # raises

// after
mcp.add_tool(greet_v1, version='1')
mcp.add_tool(greet_simple, version='1')
Defensive patterns

Strategy: validation

Validate before calling

def assert_unversioned_allowed(existing_components, new_component):
    same_name = [c for c in existing_components
                 if (c.name or c.uri) == (new_component.name or new_component.uri)]
    if any(c.version is not None for c in same_name) and new_component.version is None:
        raise ValueError('existing components are versioned; assign a version')

Type guard

def version_schemes_match(a, b) -> bool:
    return (a.version is None) == (b.version is None)

Try / catch

try:
    mcp.add_tool(legacy_tool)
except ValueError as e:
    if 'Cannot add unversioned' in str(e):
        logging.error('name is versioned; register with version=...')
    raise

Prevention

When it happens

Trigger: Calling add_tool/add_resource/add_prompt/add_template with a component lacking a version while versioned components with the same name are already registered.

Common situations: Adding a legacy unversioned copy of a tool that was already upgraded to versioned; replaying old registration code against a server that now versions its components.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/0f518bdd820c108d. Report an issue: GitHub.