{"record":{"id":"d42136ca3049d7b5","repo":"PrefectHQ/fastmcp","slug":"version-must-be-a-string-int-or-float-got-type","errorCode":null,"errorMessage":"Version must be a string, int, or float, got {type(v).__name__}: {v!r}","messagePattern":"Version must be a string, int, or float, got (.+?): (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/utilities/components.py","lineNumber":59,"sourceCode":"    if maybe_set is None:\n        return set()\n    if isinstance(maybe_set, set):\n        return maybe_set\n    return set(maybe_set)\n\n\ndef _coerce_version(v: str | int | float | None) -> str | None:\n    \"\"\"Coerce version to string, accepting int, float, or str.\n\n    Raises TypeError for non-scalar types (list, dict, set, etc.).\n    Raises ValueError if version contains '@' (used as key delimiter).\n    \"\"\"\n    if v is None:\n        return None\n    if isinstance(v, bool):\n        raise TypeError(f\"Version must be a string, int, or float, got bool: {v!r}\")\n    if not isinstance(v, (str, int, float)):\n        raise TypeError(\n            f\"Version must be a string, int, or float, got {type(v).__name__}: {v!r}\"\n        )\n    version = str(v)\n    if \"@\" in version:\n        raise ValueError(\n            f\"Version string cannot contain '@' (used as key delimiter): {version!r}\"\n        )\n    return version\n\n\nclass FastMCPComponent(FastMCPBaseModel):\n    \"\"\"Base class for FastMCP tools, prompts, resources, and resource templates.\"\"\"\n\n    KEY_PREFIX: ClassVar[str] = \"\"\n\n    def __init_subclass__(cls, **kwargs: Any) -> None:\n        super().__init_subclass__(**kwargs)\n        # Warn if a subclass doesn't define KEY_PREFIX (inherited or its own)","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/utilities/components.py#L41-L77","documentation":"Companion to the bool case: _coerce_version rejects any version value that is not str, int, or float (e.g. list, dict, None-adjacent objects) with a TypeError reporting the actual type. Versions are the component identity suffix (part of .key) so they must be scalar.","triggerScenarios":"Passing a non-scalar like a list, dict, tuple, or datetime as the version argument to a FastMCP component or transform constructor.","commonSituations":"Passing a parsed semver list like [1, 2, 0] from config; passing a settings object attribute that is a dict; forgetting to stringify a custom version type.","solutions":["Convert the version to a string/int/float before passing it, e.g. version=\".\".join(map(str, semver_list))","Fix the config source so version is a scalar","Use a simple string version like \"1.2.0\""],"exampleFix":"// before\nversion=[1, 2, 0]\nTool(fn, version=version)\n\n// after\nversion=\"1.2.0\"\nTool(fn, version=version)","handlingStrategy":"type-guard","validationCode":"if not isinstance(v, (str, int, float)) or isinstance(v, bool):\n    v = str(v)  # or normalize before passing","typeGuard":"def is_scalar_version(v: object) -> bool:\n    return isinstance(v, (str, int, float)) and not isinstance(v, bool)","tryCatchPattern":"try:\n    tool = Tool(fn, version=v)\nexcept TypeError as e:\n    if \"Version must be\" in str(e):\n        tool = Tool(fn, version=str(v))\n    else:\n        raise","preventionTips":["Store versions as plain strings in configs","Convert structured semver data to a string before use","Add a schema check on version fields in config loaders"],"tags":["python","typeerror","versioning","components"],"backgroundTag":"invalid-version-type","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}