{"record":{"id":"362f717652a39cbe","repo":"deepset-ai/haystack","slug":"this-functionhook-only-has-an-async-function-and","errorCode":null,"errorMessage":"This FunctionHook only has an `async_function` and cannot run in a synchronous Agent run. Use the Agent's async run methods, or provide a synchronous `function`.","messagePattern":"This FunctionHook only has an `async_function` and cannot run in a synchronous Agent run\\. Use the Agent's async run methods, or provide a synchronous `function`\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"haystack/hooks/from_function.py","lineNumber":78,"sourceCode":"            )\n        for func in (function, async_function):\n            if func is not None and not _takes_single_state_argument(func):\n                raise ValueError(\n                    f\"Hook function '{func.__name__}' must take a single parameter annotated with `State` \"\n                    \"(e.g. `def my_hook(state: State) -> None`).\"\n                )\n        self.function = function\n        self.async_function = async_function\n\n    def run(self, state: State) -> None:\n        \"\"\"\n        Run the synchronous function against the live `State`.\n\n        :param state: The Agent's live `State`, mutated in place by the wrapped function.\n        :raises RuntimeError: If the hook only has an `async_function`; use the Agent's async run methods instead.\n        \"\"\"\n        if self.function is None:\n            raise RuntimeError(\n                \"This FunctionHook only has an `async_function` and cannot run in a synchronous Agent run. \"\n                \"Use the Agent's async run methods, or provide a synchronous `function`.\"\n            )\n        self.function(state)\n\n    async def run_async(self, state: State) -> None:\n        \"\"\"\n        Await the async function if set, otherwise call the synchronous function.\n\n        :param state: The Agent's live `State`, mutated in place by the wrapped function.\n        \"\"\"\n        if self.async_function is not None:\n            await self.async_function(state)\n        else:\n            self.function(state)  # type: ignore[misc]  # guaranteed non-None: at least one is always set\n\n    def to_dict(self) -> dict[str, Any]:\n        \"\"\"","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/hooks/from_function.py#L60-L96","documentation":"A FunctionHook created with only an `async_function` has no synchronous implementation. When the Agent is run through sync entry points (e.g. agent.run), hooks must execute synchronously, so run() raises RuntimeError telling you to use async run methods or supply a sync `function`.","triggerScenarios":"Constructing FunctionHook(async_function=...) (or from_function with only the async callable) and then running the Agent synchronously, causing FunctionHook.run to see self.function is None.","commonSituations":"Async-only hooks in codebases that also invoke the agent via sync CLI/scripts/tests; mixing sync and async pipelines where the sync path was forgotten.","solutions":["Run the Agent with its async methods (agent.run_async / await the async run)","Provide a synchronous counterpart: FunctionHook(function=sync_fn, async_function=async_fn)","Wrap the async work in a sync function with asyncio.run if async-only is not an option"],"exampleFix":"// before\nhook = FunctionHook(async_function=my_async_hook)\nagent.run(query)  # RuntimeError\n// after\nhook = FunctionHook(function=my_sync_hook, async_function=my_async_hook)\nagent.run(query)  # works, sync path uses my_sync_hook","handlingStrategy":"try-catch","validationCode":"if hook.function is None:\n    result = await agent.run_async(query)\nelse:\n    result = agent.run(query)","typeGuard":null,"tryCatchPattern":"try:\n    result = agent.run(query)\nexcept RuntimeError as e:\n    if \"only has an `async_function`\" in str(e):\n        result = await agent.run_async(query)\n    else:\n        raise","preventionTips":["Use async run methods whenever any hook is async-only","Always provide both sync and async implementations in FunctionHook","Document at hook-registration time whether the sync path is supported"],"tags":["python","async","runtime","hooks"],"backgroundTag":"async-only-hook-in-sync-context","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}