cocoindex-io/cocoindex · error · ValueError

zvec collections require at least one vector field (dense or

Error message

zvec collections require at least one vector field (dense or sparse).

What it means

collection_target() validates that the declared schema has at least one vector field (dense or sparse) besides the primary key, since zvec is a vector collection store. A schema of only scalar columns raises ValueError.

Source

Thrown at python/cocoindex/connectors/zvec/_target.py:966

    Args:
        db: A ContextKey for the ManagedConnection (provided via lifespan).
        collection_name: Name of the collection (a subdirectory under the
            connection's base path).
        schema: Schema definition built via ``CollectionSchema.from_class``.
        managed_by: Whether CocoIndex manages the collection lifecycle
            ("system") or it must already exist ("user", documents only).
    """
    _validate_collection_name(collection_name)
    for name in schema.columns:
        if name != schema.primary_key:
            _validate_identifier(name, "field name")

    if not any(
        col.kind in ("dense", "sparse")
        for name, col in schema.columns.items()
        if name != schema.primary_key
    ):
        raise ValueError(
            "zvec collections require at least one vector field (dense or sparse)."
        )

    key = _CollectionKey(db_key=db.key, collection_name=collection_name)
    spec = _CollectionSpec(schema=schema, managed_by=managed_by)
    return _collection_provider.target_state(key, spec)


def declare_collection_target(
    db: ContextKey[ManagedConnection],
    collection_name: str,
    schema: CollectionSchema[RowT],
    *,
    managed_by: target.ManagedBy = target.ManagedBy.SYSTEM,
) -> "CollectionTarget[RowT, coco.PendingS]":
    """Declare a zvec collection target and return a CollectionTarget for rows."""
    provider = coco.declare_target_state_with_child(
        collection_target(db, collection_name, schema, managed_by=managed_by)

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Add a dense (or sparse) vector column to your record type and populate it with embeddings.
  2. Use a different (non-vector) target connector if you only need scalar storage.
  3. Check schema.columns for at least one kind in ('dense','sparse') before calling collection_target.

Example fix

// before
@dataclass
class Doc:
    id: str
    title: str
// after
@dataclass
class Doc:
    id: str
    title: str
    embedding: list[float]  # declared as dense vector column
Defensive patterns

Strategy: validation

Validate before calling

if not any(c.kind in ("dense", "sparse") for n, c in schema.columns.items() if n != schema.primary_key):
    raise ValueError("schema needs at least one vector column")

Type guard

def has_vector_column(schema) -> bool:
    return any(c.kind in ("dense", "sparse") for n, c in schema.columns.items() if n != schema.primary_key)

Try / catch

try:
    target = collection_target(db, collection_name, schema)
except ValueError as e:
    logging.error("invalid zvec schema: %s", e)

Prevention

When it happens

Trigger: Calling collection_target()/declare_collection_target()/mount_collection_target() with a record type whose columns are all scalar (no embedding/vector field).

Common situations: Forgetting to add the embedding column; a schema-refactoring step that removed the vector field; using a text-only table schema with a zvec backend.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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