PrefectHQ/fastmcp · error · ValueError
URI template must contain at least one parameter
Error message
URI template must contain at least one parameter
What it means
A resource template is defined by substituting URI template parameters into the template string. A URI with no {parameter} placeholders would always resolve to the same string, making it a static resource rather than a template, so from_function rejects it.
Source
Thrown at fastmcp_slim/fastmcp/resources/template.py:485
# same Python identifier (e.g. {user-id} and {user_id}).
all_raw = raw_path_params | raw_query_params
seen: dict[str, str] = {}
for raw_name in sorted(all_raw):
normalized = raw_name.replace("-", "_")
if normalized in seen:
raise ValueError(
f"URI template parameters '{seen[normalized]}' and "
f"'{raw_name}' both normalize to '{normalized}'. "
f"Use one or the other, not both."
)
seen[normalized] = raw_name
path_params = {p.replace("-", "_") for p in raw_path_params}
query_params = {p.replace("-", "_") for p in raw_query_params}
all_uri_params = path_params | query_params
if not all_uri_params:
raise ValueError("URI template must contain at least one parameter")
# Use wrapper to get user-facing parameters (excludes injected params)
from fastmcp.server.dependencies import (
transform_context_annotations,
without_injected_parameters,
)
wrapper_fn = without_injected_parameters(fn)
user_sig = inspect.signature(wrapper_fn)
func_params = set(user_sig.parameters.keys())
# Get required and optional function parameters
required_params = {
p
for p in func_params
if user_sig.parameters[p].default is inspect.Parameter.empty
and user_sig.parameters[p].kind != inspect.Parameter.VAR_KEYWORD
}View on GitHub (pinned to 1f02114297)
Solutions
- Add at least one {param} placeholder to the URI template
- If the URI truly has no variable parts, register it as a plain Resource (e.g. FastMCP.add_resource / Resource.from_function) instead of a template
- Fix the placeholder syntax (must be {name}) so it isn't dropped
Example fix
// before
ResourceTemplate.from_function(get_data, uri_template="data://fixed")
// after
ResourceTemplate.from_function(get_data, uri_template="data://items/{item_id}") Defensive patterns
Strategy: validation
Validate before calling
import re
def ensure_template_has_params(uri_template):
if not re.search(r"\{[^}]+\}", uri_template):
raise ValueError(f"{uri_template!r} has no {{param}}; use a plain Resource") Type guard
def is_template(uri_template) -> bool:
import re
return bool(re.search(r"\{[^}]+\}", uri_template)) Try / catch
try:
tpl = FunctionResourceTemplate.from_function(fn, uri_template=uri)
except ValueError as e:
if "at least one parameter" in str(e):
resource = Resource.from_function(fn, uri=uri) # static fallback
else:
raise Prevention
- Verify placeholder braces ({name}) aren't mangled by string formatting
- Register static URIs with add_resource, not add_template
- Unit-test that each template URI contains at least one placeholder
When it happens
Trigger: Calling ResourceTemplate.from_function with a URI template containing no {param} placeholders anywhere (path or query), e.g. uri_template="data://fixed".
Common situations: Typo like data://{param] or data://[param] that silently removes the placeholder; switching from Resource.add to a template but reusing a plain URI; building the template string programmatically and interpolating away the braces.
Related errors
- URI template parameters '{seen[normalized]}' and '{raw_name}
- Query parameters {invalid_query_params} must be optional fun
- Required function arguments {required_params} must be a subs
- URI parameters {all_uri_params} must be a subset of the func
- Expected integer, got {raw!r}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/a1d982c83cea6237.
Report an issue: GitHub.