chroma-core/chroma · error · ValueError

Keyword argument {key} is not a primitive type

Error message

Keyword argument {key} is not a primitive type

What it means

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.

Source

Thrown at chromadb/utils/embedding_functions/bm25_embedding_function.py:73

            from fastembed.sparse.bm25 import Bm25
        except ImportError:
            raise ValueError(
                "The fastembed python package is not installed. Please install it with `pip install fastembed`"
            )

        self.task = task
        self.query_config = query_config
        self.cache_dir = cache_dir
        self.k = k
        self.b = b
        self.avg_len = avg_len
        self.language = language
        self.token_max_length = token_max_length
        self.disable_stemmer = disable_stemmer
        self.specific_model_path = specific_model_path
        for key, value in kwargs.items():
            if not isinstance(value, (str, int, float, bool, list, dict, tuple)):
                raise ValueError(f"Keyword argument {key} is not a primitive type")
        self.kwargs = kwargs
        bm25_kwargs = {
            "model_name": "Qdrant/bm25",
        }
        optional_params = {
            "cache_dir": cache_dir,
            "k": k,
            "b": b,
            "avg_len": avg_len,
            "language": language,
            "token_max_length": token_max_length,
            "disable_stemmer": disable_stemmer,
            "specific_model_path": specific_model_path,
        }
        for key, value in optional_params.items():
            if value is not None:
                bm25_kwargs[key] = value
        bm25_kwargs.update({k: v for k, v in kwargs.items() if v is not None})

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Convert values to primitives before passing: str(path), int(x), float(y), plain dicts/lists.
  2. Use the dedicated typed parameters (cache_dir, k, b, language, ...) instead of pushing everything through **kwargs.
  3. Remove kwargs the Bm25 model does not actually accept.

Example fix

# before: ValueError "Keyword argument cache_path is not a primitive type"
ef = Bm25EmbeddingFunction(task="document", cache_path=Path("/tmp/cache"))

# after: use the typed parameter, or pass primitives
ef = Bm25EmbeddingFunction(task="document", cache_dir="/tmp/cache")
Defensive patterns

Strategy: type-guard

Validate before calling

def is_primitive_kwarg(value: object) -> bool:
    if isinstance(value, type):
        return False
    if isinstance(value, (str, int, float, bool)):
        return True
    if isinstance(value, (list, tuple)):
        return all(is_primitive_kwarg(v) for v in value)
    if isinstance(value, dict):
        return all(isinstance(k, str) and is_primitive_kwarg(v) for k, v in value.items())
    return False

bad = {k: v for k, v in bm25_kwargs.items() if not is_primitive_kwarg(v)}
if bad:
    raise TypeError(f"Convert these kwargs to primitives: {list(bad)}")
ef = Bm25EmbeddingFunction(task="document", **bm25_kwargs)

Type guard

def has_only_primitive_kwargs(kwargs: dict) -> bool:
    return all(is_primitive_kwarg(v) for v in kwargs.values())

Try / catch

try:
    ef = Bm25EmbeddingFunction(task="document", **kwargs)
except ValueError as e:
    if "not a primitive type" in str(e):
        kwargs = {k: (str(v) if isinstance(v, (os.PathLike,)) else v) for k, v in kwargs.items() if is_primitive_kwarg(v)}
        ef = Bm25EmbeddingFunction(task="document", **kwargs)
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16). Data as JSON: /api/errors/8ef2da50f88f2738. Report an issue: GitHub.