{"record":{"id":"731be148ee439ea3","repo":"cocoindex-io/cocoindex","slug":"either-async-fn-or-sync-fn-must-be-provided","errorCode":null,"errorMessage":"Either async_fn or sync_fn must be provided","messagePattern":"Either async_fn or sync_fn must be provided","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/_internal/function.py","lineNumber":1240,"sourceCode":"    _batchers_lock: threading.Lock\n\n    def __init__(\n        self,\n        async_fn: AsyncCallable[..., Any] | None,\n        sync_fn: Callable[..., Any] | None,\n        *,\n        memo: bool,\n        memo_key: MemoKeySpec = None,\n        batching: bool = False,\n        max_batch_size: int | None = None,\n        runner: Runner | None = None,\n        version: int | None = None,\n        logic_tracking: LogicTracking = \"full\",\n        deps: Any = None,\n    ) -> None:\n        fn = async_fn or sync_fn\n        if fn is None:\n            raise ValueError(\"Either async_fn or sync_fn must be provided\")\n        if logic_tracking is None and deps is not None:\n            raise ValueError(\n                \"deps= requires logic_tracking to be enabled; with \"\n                \"logic_tracking=None the function's logic is not tracked at \"\n                \"all, so the deps value would be silently ignored.\"\n            )\n        self._orig_async_fn = async_fn\n        self._orig_sync_fn = sync_fn\n        self._memo = memo\n        self._memo_key = _normalize_memo_key(fn, memo_key)\n        self._processor_info = core.ComponentProcessorInfo(fn.__qualname__)\n        self._logic_tracking = logic_tracking\n        self._return_deserializer = None\n        self._return_deserializer_lock = threading.Lock()\n\n        if logic_tracking is not None:\n            self._logic_fp = _compute_logic_fingerprint(fn, version=version, deps=deps)\n            core.register_logic_fingerprint(self._logic_fp)","sourceCodeStart":1222,"sourceCodeEnd":1258,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/_internal/function.py#L1222-L1258","documentation":"The @coco.fn / Function wrapper constructor requires at least one callable: either an async function (async_fn) or a sync function (sync_fn). It is thrown when both are None, which can only happen if the caller explicitly passes None or constructs the builder/wrapper without supplying a function.","triggerScenarios":"Calling Function.__init__ (or a low-level builder path) with async_fn=None and sync_fn=None, e.g. Fn(async_fn=None, sync_fn=None) or programmatic construction that forwards a variable that is None.","commonSituations":"Programmatic/metaprogramming use of coco.fn internals where the function handle is resolved dynamically (e.g. from config or a registry miss) and ends up None; typos passing the fn as an unrecognized kwarg so it is dropped and defaults to None.","solutions":["Pass the decorated function to @coco.fn (or as_async/sync variant) instead of None.","If constructing programmatically, assert the callable is not None before building the Fn wrapper.","Check kwarg spelling: the fn must arrive as async_fn= or sync_fn=, not another name."],"exampleFix":"// before\ncoco.fn(async_fn=None, sync_fn=None, memo=True)\n// after\ncoco.fn(async_fn=my_async_fn, memo=True)","handlingStrategy":"validation","validationCode":"if async_fn is None and sync_fn is None:\n    raise ValueError(\"one of async_fn/sync_fn must be a callable\")","typeGuard":"callable(async_fn) or callable(sync_fn)","tryCatchPattern":"try:\n    wrapped = coco.fn(async_fn=f)\nexcept ValueError:\n    wrapped = None","preventionTips":["Always pass the function positionally or as the correct kwarg to coco.fn.","Assert callables are non-None before programmatic builder construction."],"tags":["python","decorator","missing-argument"],"backgroundTag":"missing-required-argument","analyzedSha":"e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b","analyzedAt":"2026-09-08T15:59:19.997Z","contentChangedAt":"2026-09-08T15:59:19.997Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}