cocoindex-io/cocoindex · error · ValueError
Either async_fn or sync_fn must be provided
Error message
Either async_fn or sync_fn must be provided
What it means
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.
Source
Thrown at python/cocoindex/_internal/function.py:1240
_batchers_lock: threading.Lock
def __init__(
self,
async_fn: AsyncCallable[..., Any] | None,
sync_fn: Callable[..., Any] | None,
*,
memo: bool,
memo_key: MemoKeySpec = None,
batching: bool = False,
max_batch_size: int | None = None,
runner: Runner | None = None,
version: int | None = None,
logic_tracking: LogicTracking = "full",
deps: Any = None,
) -> None:
fn = async_fn or sync_fn
if fn is None:
raise ValueError("Either async_fn or sync_fn must be provided")
if logic_tracking is None and deps is not None:
raise ValueError(
"deps= requires logic_tracking to be enabled; with "
"logic_tracking=None the function's logic is not tracked at "
"all, so the deps value would be silently ignored."
)
self._orig_async_fn = async_fn
self._orig_sync_fn = sync_fn
self._memo = memo
self._memo_key = _normalize_memo_key(fn, memo_key)
self._processor_info = core.ComponentProcessorInfo(fn.__qualname__)
self._logic_tracking = logic_tracking
self._return_deserializer = None
self._return_deserializer_lock = threading.Lock()
if logic_tracking is not None:
self._logic_fp = _compute_logic_fingerprint(fn, version=version, deps=deps)
core.register_logic_fingerprint(self._logic_fp)View on GitHub (pinned to e84aa99b32)
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.
Example fix
// before coco.fn(async_fn=None, sync_fn=None, memo=True) // after coco.fn(async_fn=my_async_fn, memo=True)
Defensive patterns
Strategy: validation
Validate before calling
if async_fn is None and sync_fn is None:
raise ValueError("one of async_fn/sync_fn must be a callable") Type guard
callable(async_fn) or callable(sync_fn)
Try / catch
try:
wrapped = coco.fn(async_fn=f)
except ValueError:
wrapped = None Prevention
- Always pass the function positionally or as the correct kwarg to coco.fn.
- Assert callables are non-None before programmatic builder construction.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- use_mount() requires a ComponentSubpath when the function ha
- mount() requires a ComponentSubpath when the function has no
- mount_each() requires a ComponentSubpath when the function h
- Batching and runner require the function to be async. Use @c
- Async functions are not supported by @coco.fn decorator when
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/731be148ee439ea3.
Report an issue: GitHub.