deepset-ai/haystack · error · ComponentError
Method 'run_async' of component '{cls.__name__}' must be a c
Error message
Method 'run_async' of component '{cls.__name__}' must be a coroutine What it means
When a component class is instantiated, ComponentMeta.__call__ checks that run_async (if defined) is an async coroutine function via inspect.iscoroutinefunction. A plain (non-async) run_async method raises ComponentError because Haystack pipelines await run_async in async pipelines.
Source
Thrown at haystack/core/component/component.py:310
instance = super().__call__(*args, **kwargs)
else:
try:
pre_init_hook.in_progress = True
named_positional_args = ComponentMeta._positional_to_kwargs(cls, args)
assert set(named_positional_args.keys()).intersection(kwargs.keys()) == set(), (
"positional and keyword arguments overlap"
)
kwargs.update(named_positional_args)
pre_init_hook.callback(cls, kwargs)
instance = super().__call__(**kwargs)
finally:
pre_init_hook.in_progress = False
# Before returning, we have the chance to modify the newly created
# Component instance, so we take the chance and set up the I/O sockets
has_async_run = hasattr(instance, "run_async")
if has_async_run and not inspect.iscoroutinefunction(instance.run_async):
raise ComponentError(f"Method 'run_async' of component '{cls.__name__}' must be a coroutine")
instance.__haystack_supports_async__ = has_async_run
ComponentMeta._parse_and_set_input_sockets(cls, instance)
ComponentMeta._parse_and_set_output_sockets(instance)
# Since a Component can't be used in multiple Pipelines at the same time
# we need to know if it's already owned by a Pipeline when adding it to one.
# We use this flag to check that.
instance.__haystack_added_to_pipeline__ = None
return instance
def _component_repr(component: Component) -> str:
"""
All Components override their __repr__ method with this one.
It prints the component name and the input/output sockets.View on GitHub (pinned to e318778c9b)
Solutions
- Change `def run_async` to `async def run_async`
- If a decorator wraps run_async, ensure the wrapper preserves the coroutine (use functools.wraps on an async wrapper or return the coroutine function)
- If async is not needed, remove run_async and keep only run
Example fix
# before
class Echo:
@component.output_types(out=str)
def run(self, x: str):
return {"out": x}
def run_async(self, x: str): # not a coroutine
return self.run(x)
# after
class Echo:
@component.output_types(out=str)
def run(self, x: str):
return {"out": x}
@component.output_types(out=str)
async def run_async(self, x: str):
return {"out": x} Defensive patterns
Strategy: validation
Validate before calling
import inspect
if hasattr(MyComponent, "run_async") and not inspect.iscoroutinefunction(MyComponent.run_async):
raise TypeError("run_async must be declared with async def") Type guard
def is_valid_async_component(instance) -> bool:
ra = getattr(instance, "run_async", None)
return ra is None or inspect.iscoroutinefunction(ra) Try / catch
try:
comp = MyComponent()
except ComponentError as e:
if "must be a coroutine" in str(e):
logging.error("Declare run_async with 'async def'")
raise Prevention
- Always write run_async with the async def keyword
- Check any custom decorators applied to run_async preserve coroutine-ness (test with inspect.iscoroutinefunction)
- Prefer deriving run_async automatically from run via a helper that produces an async wrapper
When it happens
Trigger: Defining `def run_async(...)` without `async def` on a class decorated with @component while also having a run method; wrapping run_async with a non-async decorator that loses coroutine-ness (e.g. functools.wraps over a sync wrapper, some middleware/decorators); assigning a sync bound function to instance.run_async.
Common situations: Copy-pasting sync run into run_async but forgetting the async keyword; applying a custom decorator to run_async that returns a plain function; migrating code where run_async was previously sync-tolerated.
Related errors
- Parameters of 'run' and 'run_async' methods must be the same
- Cannot set input types on a component that doesn't have a kw
- Cannot call `set_output_types` on a component that already h
- 'output_types' decorator can only be used on 'run' and 'run_
- {cls.__name__} must have a 'run()' method. See the docs for
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/aec118789ec6b6da.
Report an issue: GitHub.