cocoindex-io/cocoindex · error · ValueError

Named-vectors dict is empty; declare at least one vector fie

Error message

Named-vectors dict is empty; declare at least one vector field.

What it means

Turbopuffer's named-vectors mode requires at least one vector field per row schema. When `create()` is given an empty dict as `vectors`, it raises ValueError because a rows-with-named-vectors setup with zero vectors is meaningless.

Source

Thrown at python/cocoindex/connectors/turbopuffer/_target.py:146

        vectors: VectorDef | dict[str, VectorDef],
        *,
        distance: DistanceMetric = "cosine_distance",
    ) -> "NamespaceSchema":
        """Create a NamespaceSchema by resolving vector definitions.

        Args:
            vectors: Either a single ``VectorDef`` (for an unnamed vector stored
                under turbopuffer's default ``"vector"`` field) or a dict mapping
                vector field names to ``VectorDef`` (for named vectors).
            distance: Distance metric applied to all vector columns in the namespace.
                Default: ``"cosine_distance"``.
        """
        resolved: _ResolvedVectorDef | _ResolvedNamedVectorsDef
        if isinstance(vectors, VectorDef):
            resolved = await _resolve_vector_def(vectors)
        elif isinstance(vectors, dict):
            if not vectors:
                raise ValueError(
                    "Named-vectors dict is empty; declare at least one vector field."
                )
            reserved = _RESERVED_VECTOR_FIELD_NAMES & set(vectors)
            if reserved:
                raise ValueError(
                    f"Vector field name {sorted(reserved)[0]!r} is reserved "
                    f"(it collides with the row id at the wire level)."
                )
            resolved = _ResolvedNamedVectorsDef(
                vectors={
                    name: await _resolve_vector_def(vd) for name, vd in vectors.items()
                }
            )
        else:
            raise ValueError(f"Invalid vector definition: {vectors}")
        return cls(resolved, distance)

    @property

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Pass at least one entry in the vectors dict, e.g. `vectors={"embedding": VectorDef(...)}`.
  2. If you meant a single unnamed vector, pass a `VectorDef` instance directly instead of a dict.
  3. Check the code that constructs the dict — an upstream filter or config may be dropping all fields.

Example fix

// before
spec = await TurbopufferTarget.create(vectors={}, distance=Metric.cosine)
// after
spec = await TurbopufferTarget.create(vectors={"embedding": VectorDef(schema="embedding_vec", dimension=384)}, distance=Metric.cosine)
Defensive patterns

Strategy: validation

Validate before calling

if isinstance(vectors, dict) and not vectors:
    raise ValueError("vectors dict must contain at least one VectorDef")

Type guard

def has_named_vectors(vectors) -> bool:
    return isinstance(vectors, dict) and len(vectors) > 0

Try / catch

try:
    spec = await Target.create(vectors=vectors_dict, distance=metric)
except ValueError as e:
    if "Named-vectors dict is empty" in str(e):
        raise RuntimeError("No vector fields configured for turbopuffer target") from e
    raise

Prevention

When it happens

Trigger: Calling the turbopuffer target `create()` with `vectors={}` (an empty dict) instead of a `VectorDef` or a non-empty dict.

Common situations: Building the vectors dict programmatically from config that ended up empty; filtering out all vector fields by mistake; default-argument misuse.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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