chroma-core/chroma · error · ValueError

Invalid task: {task}

Error message

Invalid task: {task}

What it means

When query_config is provided, embed_query ignores self.task and dispatches on query_config["task"], again accepting only "document" or "query". Any other value raises this ValueError — including None, which is what you get when the dict simply lacks the "task" key, since it is read with .get(). So passing an empty query_config={} fails with "Invalid task: None" rather than falling back to a default.

Source

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

        try:
            from fastembed.sparse.bm25 import Bm25
        except ImportError:
            raise ValueError(
                "The fastembed python package is not installed. Please install it with `pip install fastembed`"
            )
        model = cast(Bm25, self._model)
        if self.query_config is not None:
            task = self.query_config.get("task")
            if task == "document":
                embeddings = model.embed(
                    list(input),
                )
            elif task == "query":
                embeddings = model.query_embed(
                    list(input),
                )
            else:
                raise ValueError(f"Invalid task: {task}")

            sparse_vectors: SparseVectors = []

            for vec in embeddings:
                sparse_vectors.append(
                    normalize_sparse_vector(
                        indices=vec.indices.tolist(), values=vec.values.tolist()
                    )
                )

            return sparse_vectors

        else:
            return self.__call__(input)

    @staticmethod
    def name() -> str:
        return "bm25"

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Include a valid task: query_config={"task": "query"} (or "document").
  2. If you do not need per-query overrides, pass query_config=None — embed_query then reuses self.task.
  3. Validate query_config at construction: task must be present and one of the two literals.

Example fix

# before: ValueError "Invalid task: passage" (or "Invalid task: None" for missing key)
ef = Bm25EmbeddingFunction(task="query", query_config={"task": "passage"})
qv = ef.embed_query(["search term"])

# after
ef = Bm25EmbeddingFunction(task="query", query_config={"task": "query"})
qv = ef.embed_query(["search term"])
Defensive patterns

Strategy: validation

Validate before calling

VALID_TASKS = {"document", "query"}

def make_query_config(query_config: dict | None) -> dict | None:
    if query_config is None:
        return None
    task = query_config.get("task")
    if task not in VALID_TASKS:
        raise ValueError(f"query_config['task'] must be one of {sorted(VALID_TASKS)}, got {task!r}")
    return query_config

ef = Bm25EmbeddingFunction(task="query", query_config=make_query_config(raw_qcfg))

Type guard

def is_valid_query_config(qcfg: object) -> bool:
    return (
        qcfg is None
        or (isinstance(qcfg, dict) and qcfg.get("task") in ("document", "query"))
    )

Try / catch

try:
    qv = ef.embed_query(queries)
except ValueError as e:
    if "Invalid task" in str(e):
        ef.query_config = {**ef.query_config, "task": "query"}  # repair or re-construct with a valid task
        qv = ef.embed_query(queries)
    else:
        raise

Prevention

When it happens

Trigger: Bm25EmbeddingFunction(task="query", query_config={"task": "passage"}) then embed_query(...); or query_config={} / {"k": 1.5} without a "task" key — .get("task") returns None and the error reads "Invalid task: None".

Common situations: Porting sentence-transformers query configs that use "passage"; storing extra BM25 parameters (k, b) in query_config and forgetting the required task key; assuming query_config={} means "use self.task".

Related errors


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