{"record":{"id":"a1d982c83cea6237","repo":"PrefectHQ/fastmcp","slug":"uri-template-must-contain-at-least-one-parameter","errorCode":null,"errorMessage":"URI template must contain at least one parameter","messagePattern":"URI template must contain at least one parameter","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/resources/template.py","lineNumber":485,"sourceCode":"        # same Python identifier (e.g. {user-id} and {user_id}).\n        all_raw = raw_path_params | raw_query_params\n        seen: dict[str, str] = {}\n        for raw_name in sorted(all_raw):\n            normalized = raw_name.replace(\"-\", \"_\")\n            if normalized in seen:\n                raise ValueError(\n                    f\"URI template parameters '{seen[normalized]}' and \"\n                    f\"'{raw_name}' both normalize to '{normalized}'. \"\n                    f\"Use one or the other, not both.\"\n                )\n            seen[normalized] = raw_name\n\n        path_params = {p.replace(\"-\", \"_\") for p in raw_path_params}\n        query_params = {p.replace(\"-\", \"_\") for p in raw_query_params}\n        all_uri_params = path_params | query_params\n\n        if not all_uri_params:\n            raise ValueError(\"URI template must contain at least one parameter\")\n\n        # Use wrapper to get user-facing parameters (excludes injected params)\n        from fastmcp.server.dependencies import (\n            transform_context_annotations,\n            without_injected_parameters,\n        )\n\n        wrapper_fn = without_injected_parameters(fn)\n        user_sig = inspect.signature(wrapper_fn)\n        func_params = set(user_sig.parameters.keys())\n\n        # Get required and optional function parameters\n        required_params = {\n            p\n            for p in func_params\n            if user_sig.parameters[p].default is inspect.Parameter.empty\n            and user_sig.parameters[p].kind != inspect.Parameter.VAR_KEYWORD\n        }","sourceCodeStart":467,"sourceCodeEnd":503,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/resources/template.py#L467-L503","documentation":"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.","triggerScenarios":"Calling ResourceTemplate.from_function with a URI template containing no {param} placeholders anywhere (path or query), e.g. uri_template=\"data://fixed\".","commonSituations":"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.","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"],"exampleFix":"// before\nResourceTemplate.from_function(get_data, uri_template=\"data://fixed\")\n// after\nResourceTemplate.from_function(get_data, uri_template=\"data://items/{item_id}\")","handlingStrategy":"validation","validationCode":"import re\ndef ensure_template_has_params(uri_template):\n    if not re.search(r\"\\{[^}]+\\}\", uri_template):\n        raise ValueError(f\"{uri_template!r} has no {{param}}; use a plain Resource\")","typeGuard":"def is_template(uri_template) -> bool:\n    import re\n    return bool(re.search(r\"\\{[^}]+\\}\", uri_template))","tryCatchPattern":"try:\n    tpl = FunctionResourceTemplate.from_function(fn, uri_template=uri)\nexcept ValueError as e:\n    if \"at least one parameter\" in str(e):\n        resource = Resource.from_function(fn, uri=uri)  # static fallback\n    else:\n        raise","preventionTips":["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"],"tags":["uri-template","validation"],"backgroundTag":"uri-template-missing-parameter","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}