cocoindex-io/cocoindex · error · TypeError

memo_key transform for *args must return tuple, got {type(va

Error message

memo_key transform for *args must return tuple, got {type(varargs).__name__}

What it means

memo_key specifications can supply a transform (varargs_override) applied to a function's *args tuple before fingerprinting. The transform must return a tuple; any other return type raises TypeError because the result is concatenated into the final memo-key args.

Source

Thrown at python/cocoindex/_internal/function.py:481

    for i, arg in enumerate(fixed_args):
        key_fn = memo_key_plan.positional_specs[i]
        if is_not_set(key_fn):
            new_fixed_args.append(arg)
        elif key_fn is None:
            continue  # Exclude this positional arg
        else:
            new_fixed_args.append(key_fn(arg))

    # Apply varargs override if present (whole *args parameter)
    if not is_not_set(memo_key_plan.varargs_override):
        if memo_key_plan.varargs_override is None:
            # Exclude entire *args
            varargs = ()
        else:
            # Transform entire *args tuple
            varargs = memo_key_plan.varargs_override(varargs)
            if not isinstance(varargs, tuple):
                raise TypeError(
                    f"memo_key transform for *args must return tuple, "
                    f"got {type(varargs).__name__}"
                )

    # Combine fixed args and varargs
    final_args = tuple(new_fixed_args) + varargs

    # Process kwargs: separate matched (keyword-only/POSITIONAL_OR_KEYWORD passed as kwarg)
    # from unmatched (extra **kwargs)
    new_kwargs: dict[str, Any] = {}
    unmatched_kwargs: dict[str, Any] = {}

    for key, value in kwargs.items():
        if key in memo_key_plan.keyword_specs:
            key_fn = memo_key_plan.keyword_specs[key]
            if key_fn is None:
                continue  # Exclude this kwarg
            new_kwargs[key] = key_fn(value)

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Return a tuple from the varargs transform: tuple(transformed)
  2. Wrap single values: (value,)
  3. Materialize generators/lists into a tuple before returning

Example fix

# before
def key(*args):
    return [normalize(a) for a in args]

# after
def key(*args):
    return tuple(normalize(a) for a in args)
Defensive patterns

Strategy: validation

Validate before calling

def as_tuple(result):
    if not isinstance(result, tuple):
        raise TypeError("varargs transform must return tuple")
    return result

Type guard

def is_tuple(x: object) -> TypeGuard[tuple]:
    return isinstance(x, tuple)

Prevention

When it happens

Trigger: @coco.fn(memo_key={"*": transform}) (or MemoKeySpec with varargs override) where transform returns a list, generator, or single value instead of a tuple, for a function accepting *args.

Common situations: Writing `return [x for x in args]` in a transform; forgetting to wrap a single normalized value in a tuple; converting args to a string for logging and returning it.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08). Data as JSON: /api/errors/65df8370f52aaf15. Report an issue: GitHub.