PrefectHQ/fastmcp · error · KeyError

Template {uri_template!r} not found

Error message

Template {uri_template!r} not found

What it means

remove_template(uri_template, version=None) matches ResourceTemplate components by their exact uri_template string; with no match it raises KeyError(f"Template {uri_template!r} not found"). Note the match is against the pattern itself, not concrete URIs derived from it.

Source

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

    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
            ]
            if not keys_to_remove:
                raise KeyError(f"Template {uri_template!r} not found")
            for key in keys_to_remove:
                self._remove_component(key)
        else:
            # Remove specific version
            key = f"{ResourceTemplate.make_key(uri_template)}@{version}"
            if key not in self._components:
                raise KeyError(
                    f"Template {uri_template!r} version {version!r} not found"
                )
            self._remove_component(key)

    def remove_prompt(self, name: str, version: str | None = None) -> None:
        """Remove prompt(s) from this provider's storage.

        Args:
            name: The prompt name.
            version: If None, removes ALL versions. If specified, removes only that version.

View on GitHub (pinned to 1f02114297)

Solutions

  1. Pass the exact pattern string used at registration, placeholders included
  2. List registered ResourceTemplates and copy the uri_template verbatim
  3. Catch KeyError for idempotent teardown

Example fix

// before
provider.remove_template("weather/{city}")  # registered as "weather://{city}"
// after
provider.remove_template("weather://{city}")
Defensive patterns

Strategy: validation

Validate before calling

patterns = {c.uri_template for c in provider._components.values()
            if isinstance(c, ResourceTemplate)}
if "weather://{city}" not in patterns:
    return

Type guard

def template_exists(provider, uri_template: str) -> bool:
    return any(isinstance(c, ResourceTemplate) and c.uri_template == uri_template
               for c in provider._components.values())

Try / catch

try:
    provider.remove_template("weather://{city}")
except KeyError:
    pass  # template not registered

Prevention

When it happens

Trigger: provider.remove_template("weather://{city}") where the template was registered with a different pattern string (different placeholder names, braces style, or path) or was never added to this provider.

Common situations: Pattern-string drift after refactoring placeholder names ({city} vs {location}); attempting removal with a concrete URI instead of the template pattern; template registered on another provider.

Related errors


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