{"record":{"id":"eef1c2d6f47985bf","repo":"deepset-ai/haystack","slug":"output-types-decorator-can-only-be-used-on-run","errorCode":null,"errorMessage":"'output_types' decorator can only be used on 'run' and 'run_async' methods","messagePattern":"'output_types' decorator can only be used on 'run' and 'run_async' methods","errorType":"exception","errorClass":"ComponentError","httpStatus":null,"severity":"error","filePath":"haystack/core/component/component.py","lineNumber":552,"sourceCode":"        class MyComponent:\n            @component.output_types(output_1=int, output_2=str)\n            def run(self, value: int):\n                return {\"output_1\": 1, \"output_2\": \"2\"}\n        ```\n        \"\"\"\n\n        def output_types_decorator(run_method: Callable[RunParamsT, RunReturnT]) -> Callable[RunParamsT, RunReturnT]:\n            \"\"\"\n            Decorator that sets the output types of the decorated method.\n\n            This happens at class creation time, and since we don't have the decorated\n            class available here, we temporarily store the output types as an attribute of\n            the decorated method. The ComponentMeta metaclass will use this data to create\n            sockets at instance creation time.\n            \"\"\"\n            method_name = run_method.__name__\n            if method_name not in (\"run\", \"run_async\"):\n                raise ComponentError(\"'output_types' decorator can only be used on 'run' and 'run_async' methods\")\n\n            setattr(  # noqa: B010\n                run_method,\n                \"_output_types_cache\",\n                {name: OutputSocket(name=name, type=type_) for name, type_ in types.items()},\n            )\n            return run_method\n\n        return output_types_decorator\n\n    def _component(self, cls: type[T]) -> type[T]:\n        \"\"\"\n        Decorator validating the structure of the component and registering it in the components registry.\n        \"\"\"\n        logger.debug(\"Registering {component} as a component\", component=cls)\n\n        # Check for required methods and fail as soon as possible\n        if not hasattr(cls, \"run\"):","sourceCodeStart":534,"sourceCodeEnd":570,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/core/component/component.py#L534-L570","documentation":"The @component.output_types decorator declares a component's output sockets and may only decorate the component's entrypoint methods. Haystack raises this ComponentError during decoration when the decorated method is anything other than 'run' or 'run_async', because output types can only be attached to those methods (ComponentMeta later reads the cached sockets from them).","triggerScenarios":"Applying @component.output_types(SomeType) to any method other than run or run_async — e.g. a helper method, a __init__, a custom named method, or applying it at module level to a plain function.","commonSituations":"Refactoring a component and accidentally decorating a private helper; typos like @output_types on 'run_sync'; copy-pasting the decorator onto a callback; trying to declare outputs for multiple methods.","solutions":["Move the @component.output_types decorator so it directly wraps the 'run' (or 'run_async') method","If outputs differ for async, decorate both 'run' and 'run_async' separately with @component.output_types","Remove the decorator from non-entrypoint helper methods and return a dataclass/dict typed via run's decorator instead"],"exampleFix":"// before\nclass MyComponent:\n    @component.output_types(str)\n    def prepare(self, x: int) -> str: ...\n\n    def run(self, x: int) -> dict[str, str]: ...\n\n// after\nclass MyComponent:\n    def prepare(self, x: int) -> str: ...\n\n    @component.output_types(str)\n    def run(self, x: int) -> dict[str, str]: ...","handlingStrategy":"validation","validationCode":"def ensure_output_types_on_run(cls) -> None:\n    for name, member in vars(cls).items():\n        if hasattr(member, \"_output_types_cache\") and name not in (\"run\", \"run_async\"):\n            raise TypeError(f\"@output_types is on '{name}'; only 'run'/'run_async' are allowed\")","typeGuard":"def is_runlike(obj) -> bool:\n    return callable(obj) and getattr(obj, \"__name__\", None) in (\"run\", \"run_async\")","tryCatchPattern":"try:\n    component.output_types(str)(my_func)\nexcept ComponentError as e:\n    logging.error(\"output_types applied to non-run method: %s\", e)","preventionTips":["Only ever stack @component.output_types directly above 'def run' or 'async def run_async'","Run a quick import/smoke test of component modules in CI","Never copy the decorator onto helper methods during refactors"],"tags":["python","decorator","component","haystack"],"backgroundTag":"decorator-applied-to-wrong-target","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}