{"record":{"id":"95ec4376bbabb1a7","repo":"PrefectHQ/fastmcp","slug":"name-uses-a-sync-function-but-has-task-executi","errorCode":null,"errorMessage":"'{name}' uses a sync function but has task execution enabled. Background tasks require async functions.","messagePattern":"'(.+?)' uses a sync function but has task execution enabled\\. Background tasks require async functions\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/utilities/tasks.py","lineNumber":80,"sourceCode":"        return self.mode != \"forbidden\"\n\n    def validate_function(self, fn: Callable[..., Any], name: str) -> None:\n        \"\"\"Validate that a function is compatible with this task config.\"\"\"\n        if not self.supports_tasks():\n            return\n\n        fn_to_check = fn\n        if (\n            not inspect.isroutine(fn)\n            and not isinstance(fn, functools.partial)\n            and callable(fn)\n        ):\n            fn_to_check = fn.__call__\n        if isinstance(fn_to_check, staticmethod):\n            fn_to_check = fn_to_check.__func__\n\n        if not is_coroutine_function(fn_to_check):\n            raise ValueError(\n                f\"'{name}' uses a sync function but has task execution enabled. \"\n                \"Background tasks require async functions.\"\n            )\n","sourceCodeStart":62,"sourceCodeEnd":84,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/utilities/tasks.py#L62-L84","documentation":"FastMCP raises this ValueError when a component (tool, resource, prompt) is configured with task execution enabled but the underlying callable is a synchronous function. Background task execution is implemented with asyncio, so only coroutine functions can be scheduled to run in the background. The check runs during component construction via from_function, failing fast rather than at task submission time.","triggerScenarios":"Calling Tool.from_function / Resource.from_function / Prompt.from_function (or decorators like @mcp.tool) on a plain `def` function while passing task execution enabled (e.g. task=True or an execution/task config). The check inspects fn (or fn.__call__ / staticmethod __func__) with is_coroutine_function and raises when it returns False.","commonSituations":"Developers write a sync helper (doing blocking I/O or CPU work) and enable background task mode so it runs 'async', not realizing async scheduling requires a coroutine function. Also common after refactoring an async function to sync while leaving task config in place, or wrapping functions where the wrapper is sync.","solutions":["Convert the function to an async def function (awaiting async I/O or wrapping blocking work with asyncio.to_thread)","Keep the function sync but disable task execution for the component (remove the task=True / task execution config)","If blocking work must stay sync but be non-blocking, create an async wrapper that calls asyncio.to_thread(sync_fn, ...) and register the wrapper with task execution enabled","If using a callable object or staticmethod, ensure the __call__/__func__ actually is a coroutine function, since the check unwraps those"],"exampleFix":"// before\n@mcp.tool(task=True)\ndef fetch_data(url: str) -> str:\n    return requests.get(url).text\n\n// after\n@mcp.tool(task=True)\nasync def fetch_data(url: str) -> str:\n    return await asyncio.to_thread(requests.get, url).text","handlingStrategy":"validation","validationCode":"import asyncio\nif not asyncio.iscoroutinefunction(fn):\n    raise TypeError(f\"{fn.__name__} must be async def when task execution is enabled\")","typeGuard":"def is_async_fn(fn) -> bool:\n    import asyncio\n    target = fn.__func__ if isinstance(fn, staticmethod) else getattr(fn, \"__call__\", fn)\n    return asyncio.iscoroutinefunction(target)","tryCatchPattern":null,"preventionTips":["Make background-task components async def by convention","Wrap blocking I/O with asyncio.to_thread instead of registering sync functions","Re-check task flags after refactoring functions between sync and async"],"tags":["python","async","tasks","configuration"],"backgroundTag":"sync-function-with-async-task-config","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}