{"record":{"id":"3fb637309fca3c8f","repo":"cocoindex-io/cocoindex","slug":"unknown-memo-key-parameter-s-for-qualified-name","errorCode":null,"errorMessage":"Unknown memo_key parameter(s) for {qualified_name(fn)}(): {', '.join(unknown)}","messagePattern":"Unknown memo_key parameter\\(s\\) for (.+?)\\(\\): (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/_internal/function.py","lineNumber":539,"sourceCode":"    return final_args, new_kwargs\n\n\ndef _normalize_memo_key(\n    fn: Callable[..., Any], memo_key: MemoKeySpec\n) -> PreparedMemoKeySpec | None:\n    \"\"\"Validate and compile per-parameter memo-key overrides once.\"\"\"\n    if memo_key is None:\n        return None\n\n    normalized = dict(memo_key)\n    if not normalized:\n        return None\n\n    sig = inspect.signature(fn)\n    param_names = {param.name for param in sig.parameters.values()}\n    unknown = sorted(name for name in normalized if name not in param_names)\n    if unknown:\n        raise ValueError(\n            f\"Unknown memo_key parameter(s) for {qualified_name(fn)}(): \"\n            + \", \".join(unknown)\n        )\n\n    for name, transform in normalized.items():\n        if transform is not None and not callable(transform):\n            raise TypeError(\n                f\"memo_key[{name!r}] for {qualified_name(fn)}() must be a callable or None\"\n            )\n\n    positional: list[MemoKeyTransform | None | NotSetType] = []\n    varargs_override: MemoKeyTransform | None | NotSetType = NOT_SET\n    varkw_override: MemoKeyTransform | None | NotSetType = NOT_SET\n\n    for param in sig.parameters.values():\n        if param.kind in (\n            inspect.Parameter.POSITIONAL_ONLY,\n            inspect.Parameter.POSITIONAL_OR_KEYWORD,","sourceCodeStart":521,"sourceCodeEnd":557,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/_internal/function.py#L521-L557","documentation":"At decorator construction, memo_key parameter names are validated against the function's signature. Naming a parameter that the function doesn't declare raises ValueError, catching typos before any call happens.","triggerScenarios":"@coco.fn(memo_key={\"parma\": None}) or any misspelled/nonexistent parameter name in the memo_key mapping for the decorated function.","commonSituations":"Typos in memo_key keys; renaming function parameters without updating memo_key; copying memo_key specs between similar functions with different parameter names.","solutions":["Correct the memo_key key to match an actual parameter of the function","Check inspect.signature(fn) / the function definition for exact parameter names","Remove memo_key entries for parameters that no longer exist after a rename"],"exampleFix":"# before\n@coco.fn(memo_key={\"parma\": None})\nasync def f(param: str): ...\n\n# after\n@coco.fn(memo_key={\"param\": None})\nasync def f(param: str): ...","handlingStrategy":"validation","validationCode":"import inspect\nbad = set(memo_key) - set(inspect.signature(fn).parameters)\nassert not bad, f\"unknown memo_key params: {bad}\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep memo_key keys identical to parameter names — copy-paste from the signature","Update memo_key whenever renaming function parameters","Import-time decoration already raises; catch typos in CI by importing the module"],"tags":["memoization","decorator-config","validation"],"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"}