{"record":{"id":"8ef2da50f88f2738","repo":"chroma-core/chroma","slug":"keyword-argument-key-is-not-a-primitive-type-8ef2da","errorCode":null,"errorMessage":"Keyword argument {key} is not a primitive type","messagePattern":"Keyword argument (.+?) is not a primitive type","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"chromadb/utils/embedding_functions/bm25_embedding_function.py","lineNumber":73,"sourceCode":"            from fastembed.sparse.bm25 import Bm25\n        except ImportError:\n            raise ValueError(\n                \"The fastembed python package is not installed. Please install it with `pip install fastembed`\"\n            )\n\n        self.task = task\n        self.query_config = query_config\n        self.cache_dir = cache_dir\n        self.k = k\n        self.b = b\n        self.avg_len = avg_len\n        self.language = language\n        self.token_max_length = token_max_length\n        self.disable_stemmer = disable_stemmer\n        self.specific_model_path = specific_model_path\n        for key, value in kwargs.items():\n            if not isinstance(value, (str, int, float, bool, list, dict, tuple)):\n                raise ValueError(f\"Keyword argument {key} is not a primitive type\")\n        self.kwargs = kwargs\n        bm25_kwargs = {\n            \"model_name\": \"Qdrant/bm25\",\n        }\n        optional_params = {\n            \"cache_dir\": cache_dir,\n            \"k\": k,\n            \"b\": b,\n            \"avg_len\": avg_len,\n            \"language\": language,\n            \"token_max_length\": token_max_length,\n            \"disable_stemmer\": disable_stemmer,\n            \"specific_model_path\": specific_model_path,\n        }\n        for key, value in optional_params.items():\n            if value is not None:\n                bm25_kwargs[key] = value\n        bm25_kwargs.update({k: v for k, v in kwargs.items() if v is not None})","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/utils/embedding_functions/bm25_embedding_function.py#L55-L91","documentation":"Like other configurable embedding functions, Bm25EmbeddingFunction stores its **kwargs verbatim in get_config() so the function can be serialized and rebuilt later. To keep that persistence JSON-safe, the constructor rejects any kwarg value that is not a primitive (str, int, float, bool, list, dict, tuple) with this ValueError naming the offending key. fastembed model options must therefore be passed as plain data, not objects.","triggerScenarios":"Bm25EmbeddingFunction(task=\"document\", some_option=<object>) — e.g. passing a pathlib.Path, a numpy scalar, a config object, or a callable as one of the **kwargs forwarded to the Bm25 model.","commonSituations":"Passing Path objects for cache_dir-style options (cache_dir has its own typed parameter — objects only arrive via **kwargs); forwarding settings dicts from other frameworks that contain wrapped types; numpy bools/ints sneaking in from tuned parameters.","solutions":["Convert values to primitives before passing: str(path), int(x), float(y), plain dicts/lists.","Use the dedicated typed parameters (cache_dir, k, b, language, ...) instead of pushing everything through **kwargs.","Remove kwargs the Bm25 model does not actually accept."],"exampleFix":"# before: ValueError \"Keyword argument cache_path is not a primitive type\"\nef = Bm25EmbeddingFunction(task=\"document\", cache_path=Path(\"/tmp/cache\"))\n\n# after: use the typed parameter, or pass primitives\nef = Bm25EmbeddingFunction(task=\"document\", cache_dir=\"/tmp/cache\")","handlingStrategy":"type-guard","validationCode":"def is_primitive_kwarg(value: object) -> bool:\n    if isinstance(value, type):\n        return False\n    if isinstance(value, (str, int, float, bool)):\n        return True\n    if isinstance(value, (list, tuple)):\n        return all(is_primitive_kwarg(v) for v in value)\n    if isinstance(value, dict):\n        return all(isinstance(k, str) and is_primitive_kwarg(v) for k, v in value.items())\n    return False\n\nbad = {k: v for k, v in bm25_kwargs.items() if not is_primitive_kwarg(v)}\nif bad:\n    raise TypeError(f\"Convert these kwargs to primitives: {list(bad)}\")\nef = Bm25EmbeddingFunction(task=\"document\", **bm25_kwargs)","typeGuard":"def has_only_primitive_kwargs(kwargs: dict) -> bool:\n    return all(is_primitive_kwarg(v) for v in kwargs.values())","tryCatchPattern":"try:\n    ef = Bm25EmbeddingFunction(task=\"document\", **kwargs)\nexcept ValueError as e:\n    if \"not a primitive type\" in str(e):\n        kwargs = {k: (str(v) if isinstance(v, (os.PathLike,)) else v) for k, v in kwargs.items() if is_primitive_kwarg(v)}\n        ef = Bm25EmbeddingFunction(task=\"document\", **kwargs)\n    else:\n        raise","preventionTips":["Use the typed constructor parameters (cache_dir, k, b, language, ...) instead of **kwargs where possible.","Coerce Path and numpy types to str/int/float at your config boundary.","Run a primitive-check over any config you intend to persist via get_config()."],"tags":["python","fastembed","bm25","serialization","type-validation","chromadb"],"backgroundTag":"non-serializable-config-value","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}