PrefectHQ/fastmcp · error · KeyError

Resource {uri!r} version {version!r} not found

Error message

Resource {uri!r} version {version!r} not found

What it means

remove_resource with an explicit version constructs f"{Resource.make_key(uri)}@{version}" and raises KeyError if that exact key is not stored. The URI may exist but not with the supplied version string.

Source

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

        Raises:
            KeyError: If no matching resource is found.
        """
        if version is None:
            # Remove all versions
            keys_to_remove = [
                k
                for k, c in self._components.items()
                if isinstance(c, Resource) and str(c.uri) == uri
            ]
            if not keys_to_remove:
                raise KeyError(f"Resource {uri!r} not found")
            for key in keys_to_remove:
                self._remove_component(key)
        else:
            # Remove specific version
            key = f"{Resource.make_key(uri)}@{version}"
            if key not in self._components:
                raise KeyError(f"Resource {uri!r} version {version!r} not found")
            self._remove_component(key)

    def remove_template(self, uri_template: str, version: str | None = None) -> None:
        """Remove resource template(s) from this provider's storage.

        Args:
            uri_template: The template URI pattern.
            version: If None, removes ALL versions. If specified, removes only that version.

        Raises:
            KeyError: If no matching template is found.
        """
        if version is None:
            # Remove all versions
            keys_to_remove = [
                k
                for k, c in self._components.items()
                if isinstance(c, ResourceTemplate) and c.uri_template == uri_template

View on GitHub (pinned to 1f02114297)

Solutions

  1. Omit the version argument to remove all versions of the resource
  2. Check the registered version string matches exactly before removal
  3. Catch KeyError for idempotent teardown

Example fix

// before
provider.remove_resource("config://app", "2.0")  # registered as "2"
// after
provider.remove_resource("config://app")  # removes all versions
Defensive patterns

Strategy: validation

Validate before calling

key = f"{Resource.make_key('config://app')}@1.0"
if key not in provider._components:
    provider.remove_resource("config://app")  # all versions

Type guard

def resource_version_registered(provider, uri: str, version: str) -> bool:
    return f"{Resource.make_key(uri)}@{version}" in provider._components

Try / catch

try:
    provider.remove_resource("config://app", "1.0")
except KeyError:
    logger.info("resource version not present; nothing removed")

Prevention

When it happens

Trigger: provider.remove_resource("config://app", "2") when the resource is registered unversioned, versioned as "2.0", or under a different version value.

Common situations: Version drift between add and remove calls; assuming a version exists after partial cleanup; mixing versioned and unversioned registration styles.

Related errors


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