PrefectHQ/fastmcp · error
ToolTransform has duplicate target name {target!r}: both {se
Error message
ToolTransform has duplicate target name {target!r}: both {seen_targets[target]!r} and {original_name!r} map to it What it means
ToolTransform validates that every transformed tool maps to a unique public target name. Each entry's target name is its explicit `name` if set, otherwise the original tool name. If two entries resolve to the same target, the transform map would be ambiguous at lookup time, so the constructor raises ValueError immediately.
Source
Thrown at fastmcp_slim/fastmcp/server/transforms/tool_transform.py:52
"""Initialize ToolTransform.
Args:
transforms: Map of original tool name → transform config.
"""
self._transforms = transforms
# Build reverse mapping: final_name → original_name
self._name_reverse: dict[str, str] = {}
for original_name, config in transforms.items():
final_name = config.name if config.name else original_name
self._name_reverse[final_name] = original_name
# Validate no duplicate target names
seen_targets: dict[str, str] = {}
for original_name, config in transforms.items():
target = config.name if config.name else original_name
if target in seen_targets:
raise ValueError(
f"ToolTransform has duplicate target name {target!r}: "
f"both {seen_targets[target]!r} and {original_name!r} map to it"
)
seen_targets[target] = original_name
def __repr__(self) -> str:
names = list(self._transforms.keys())
if len(names) <= 3:
return f"ToolTransform({names!r})"
return f"ToolTransform({names[:3]!r}... +{len(names) - 3} more)"
async def list_tools(self, tools: Sequence[Tool]) -> Sequence[Tool]:
"""Apply transforms to matching tools."""
result: list[Tool] = []
for tool in tools:
if tool.name in self._transforms:
transformed = self._transforms[tool.name].apply(tool)
result.append(transformed)View on GitHub (pinned to 1f02114297)
Solutions
- Pick a distinct `name` for one of the colliding transform entries so targets are unique.
- Remove one of the duplicate entries if it is redundant (e.g. left over from an old config).
- Prefix or namespace generated target names (e.g. `api_<tool>`) in scripted configs to avoid accidental collisions.
Example fix
# before
transforms = ToolTransform({
"list_items": ToolTransformConfig(name="items"),
"get_items": ToolTransformConfig(name="items"), # duplicate target 'items'
})
# after
transforms = ToolTransform({
"list_items": ToolTransformConfig(name="list_items_view"),
"get_items": ToolTransformConfig(name="get_items_view"),
}) Defensive patterns
Strategy: validation
Validate before calling
targets = [(k, c.name or k) for k, c in transforms.items()]
dups = [t for t in set(x[1] for x in targets) if [x[1] for x in targets].count(t) > 1]
if dups:
raise ValueError(f"Duplicate transform target names: {dups}") Try / catch
try:
t = ToolTransform(transforms)
except ValueError as e:
if "duplicate target name" in str(e):
log.error(f"Transform config conflict: {e}")
raise SystemExit(2) Prevention
- Centralize tool renaming in one config and assert uniqueness in tests.
- Namespace scripted target names to avoid accidental collisions.
- Lint transform dicts for duplicate resolved targets in CI.
When it happens
Trigger: Calling `ToolTransform({...})` (or a subclass like the renaming transform) with a dict where two entries produce the same target: e.g. two entries renaming different originals to the same new name, or an explicit `name` on one entry colliding with another entry's original tool name.
Common situations: Bulk-renaming configs generated by hand or script where a rename accidentally matches an existing tool name; copying a transform config between environments where one tool was renamed upstream; adding a new renamed entry without noticing the target name already exists.
Related errors
- At least one of version_gte or version_lt must be specified
- Cannot resolve tool reference: {fn!r}
- Cannot determine tool name for {fn!r}
- File {name!r} not found. Available: {available}
- File {f.get('name', '?')!r} exceeds max size ({_format_size(
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/90a208ec64da05cc.
Report an issue: GitHub.