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)
@propertyView on GitHub (pinned to e84aa99b32)
Solutions
- Pass at least one entry in the vectors dict, e.g. `vectors={"embedding": VectorDef(...)}`.
- If you meant a single unnamed vector, pass a `VectorDef` instance directly instead of a dict.
- 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
- Assert the vectors dict is non-empty right after building it from config.
- Fall back to a single VectorDef when only one vector field exists.
- Add a startup check that every target has at least one declared vector field.
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
- Invalid vector dimension: {vector_schema.size}
- Invalid vector dimension: {vector_schema.size}
- Invalid vector definition: {vector_def}
- Vector field name {sorted(reserved)[0]!r} is reserved (it co
- Invalid vector definition: {vectors}
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/e692d2e51722b267.
Report an issue: GitHub.