PrefectHQ/fastmcp · error · KeyError
Component {key!r} not found
Error message
Component {key!r} not found What it means
LocalProvider stores all components (tools, resources, templates, prompts) in a single dict keyed by prefixed keys like "tool:name" or "resource:uri". _remove_component deletes an entry by key, and raises KeyError when the key is absent from storage. It is an internal helper invoked by the public remove_tool/remove_resource/remove_template/remove_prompt methods after their own lookups.
Source
Thrown at fastmcp_slim/fastmcp/server/providers/local_provider/local_provider.py:214
# Check for versioned/unversioned mixing before adding
self._check_version_mixing(component)
self._components[component.key] = component
return component
def _remove_component(self, key: str) -> None:
"""Remove a component from unified storage.
Args:
key: The prefixed key of the component.
Raises:
KeyError: If the component is not found.
"""
component = self._components.get(key)
if component is None:
raise KeyError(f"Component {key!r} not found")
del self._components[key]
def _get_component(self, key: str) -> FastMCPComponent | None:
"""Get a component by its prefixed key.
Args:
key: The prefixed key (e.g., "tool:name", "resource:uri").
Returns:
The component, or None if not found.
"""
return self._components.get(key)
def remove_tool(self, name: str, version: str | None = None) -> None:
"""Remove tool(s) from this provider's storage.
Args:View on GitHub (pinned to 1f02114297)
Solutions
- Verify the exact key with provider._get_component(key) or by listing components before removal
- Catch KeyError and treat as a no-op if idempotent removal is intended
- Use the public remove_tool/remove_resource/remove_template/remove_prompt APIs instead, which accept names/URIs and give more descriptive errors
Example fix
// before
provider._remove_component("tool:greet") # KeyError if not present
// after
if provider._get_component("tool:greet") is not None:
provider._remove_component("tool:greet") Defensive patterns
Strategy: try-catch
Validate before calling
key = "tool:my_tool"
if provider._get_component(key) is None:
return # nothing to remove Type guard
def has_component(provider, key: str) -> bool:
return provider._get_component(key) is not None Try / catch
try:
provider._remove_component(key)
except KeyError:
pass # already absent; treat as idempotent success Prevention
- Prefer the public remove_* APIs over the internal _remove_component
- Build keys from component.key or Type.make_key(), never by hand
- Make teardown/removal logic idempotent by swallowing KeyError
When it happens
Trigger: Directly calling provider._remove_component(key) with a key string that is not currently in the provider's _components dict — e.g. a typo in the prefixed key, a component that was already removed, or a key from a different provider.
Common situations: Test code or custom provider subclasses manipulating the internal dict directly; double-removal in teardown logic; using a raw name instead of the prefixed key form produced by FastMCPComponent.key.
Related errors
- Tool {name!r} not found
- Tool {name!r} version {version!r} not found
- Resource {uri!r} not found
- Resource {uri!r} version {version!r} not found
- Template {uri_template!r} not found
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/73ef19efd64c9a54.
Report an issue: GitHub.