cocoindex-io/cocoindex · error · ValueError

Unsupported dense vector dtype

Error message

Unsupported dense vector dtype {dtype!r}; zvec dense vectors must be float32 or float16. For compressed storage, use a float32 vector with ZvecVectorDef(quantize="int8").

What it means

zvec dense vector columns only support float32 and float16 dtypes. _dense_vector_data_type raises ValueError for any other numpy dtype (e.g. float64, bfloat16, int8), and points to ZvecVectorDef(quantize="int8") for compressed storage.

Solutions

  1. Cast vectors to np.float32 (v.astype(np.float32)) before indexing
  2. Or use np.float16 if half precision is acceptable
  3. For smaller storage, keep float32 and set ZvecVectorDef(quantize="int8")

Example fix

// before
vec: Annotated[np.ndarray, VectorSchema(size=768)]  # float64 from model
// after
vec: Annotated[np.ndarray, VectorSchema(size=768)] = np.zeros(768, dtype=np.float32)
Defensive patterns

Strategy: validation

Validate before calling

assert vectors.dtype in (np.float32, np.float16), f"unsupported dtype {vectors.dtype}; cast to float32"

Type guard

def is_zvec_vector_dtype(a: np.ndarray) -> bool:
    return a.dtype in (np.float32, np.float16)

Try / catch

try:
    schema = ZvecCollection.from_class(Row)
except ValueError as e:
    if "Unsupported dense vector dtype" in str(e):
        vectors = vectors.astype(np.float32)
    else:
        raise

Prevention

When it happens

Trigger: Declaring a vector column whose numpy ndarray annotation/override has dtype float64, bfloat16, int8, etc., resolved via _resolve_column in from_class.

Common situations: Embeddings produced by a model/lib in float64 or bfloat16 passed straight through; loading vectors with np.array without dtype=float32.

Related errors


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

Appendix: source

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

    str: _zvec.DataType.ARRAY_STRING,
    int: _zvec.DataType.ARRAY_INT64,
    float: _zvec.DataType.ARRAY_DOUBLE,
    bool: _zvec.DataType.ARRAY_BOOL,
}


def _json_encoder(value: Any) -> str:
    return json.dumps(value, default=str)


def _dense_vector_data_type(dtype: np.dtype) -> Any:
    # zvec's dense vector index only accepts FP32 and FP16. For smaller storage,
    # keep an FP32 vector and set quantize on ZvecVectorDef (e.g. "int8").
    if dtype == np.float32:
        return _zvec.DataType.VECTOR_FP32
    if dtype == np.float16:
        return _zvec.DataType.VECTOR_FP16
    raise ValueError(
        f"Unsupported dense vector dtype {dtype!r}; zvec dense vectors must be "
        "float32 or float16. For compressed storage, use a float32 vector with "
        'ZvecVectorDef(quantize="int8").'
    )


def _scalar_data_type(type_info: Any) -> tuple[Any, ValueEncoder | None]:
    base_type = type_info.base_type
    if base_type in _LEAF_SCALAR_MAPPINGS:
        return _LEAF_SCALAR_MAPPINGS[base_type]
    if isinstance(type_info.variant, SequenceType):
        elem_info = analyze_type_info(type_info.variant.elem_type)
        mapped = _ARRAY_ELEM_MAPPINGS.get(elem_info.base_type)
        if mapped is not None:
            return mapped, None
    # Fallback: store complex/unknown types as a JSON string.
    return _zvec.DataType.STRING, _json_encoder

View on GitHub (pinned to e84aa99b32)