RyanCodrai/turbovec · error · ValueError

TurboQuantVectorDb supports distance=Distance.cosine or dist

Error message

TurboQuantVectorDb supports distance=Distance.cosine or distance=Distance.max_inner_product; got {distance}. L2 distance is not supported by the underlying inner-product kernel.

What it means

The underlying quantized kernel computes inner products, so TurboQuantVectorDb supports only Distance.cosine and Distance.max_inner_product. L2 (euclidean) distance cannot be served correctly and raises a ValueError at construction.

Source

Thrown at turbovec-python/python/turbovec/agno.py:198

            similarity_threshold=similarity_threshold,
        )
        if embedder is None:
            raise ValueError(
                "`embedder` is required; turbovec needs the embedder's "
                "`dimensions` to size the underlying index."
            )
        if embedder.dimensions is None:
            raise ValueError("Embedder.dimensions must be set.")
        if bit_width not in (2, 3, 4):
            raise ValueError(f"bit_width must be 2, 3, or 4, got {bit_width}")
        if search_type != SearchType.vector:
            raise ValueError(
                f"TurboQuantVectorDb only supports search_type=SearchType.vector; "
                f"got {search_type}. Use LanceDb / Chroma / etc. for keyword "
                f"or hybrid search."
            )
        if distance not in (Distance.cosine, Distance.max_inner_product):
            raise ValueError(
                f"TurboQuantVectorDb supports distance=Distance.cosine or "
                f"distance=Distance.max_inner_product; got {distance}. "
                f"L2 distance is not supported by the underlying "
                f"inner-product kernel."
            )

        self.embedder: Embedder = embedder
        self.dimensions: int = embedder.dimensions
        self.bit_width = bit_width
        # Assigned through the validating property below, so the guard
        # applies to runtime mutation as well as construction.
        self.search_type = search_type
        self.distance = distance
        self.reranker = reranker
        self.path: Optional[str] = path

        # Lazy: the underlying IdMapIndex is created by `create()`, not
        # in __init__. This matches LanceDb's `exists()` contract: a

View on GitHub (pinned to ccab9f325e)

Solutions

  1. Set distance=Distance.cosine (most common for text embeddings).
  2. Use distance=Distance.max_inner_product if your scores are inner-product-like (e.g. MIPS).
  3. If L2 is mandatory, choose a backend whose kernel supports euclidean distance.

Example fix

// before
TurboQuantVectorDb(embedder=e, distance=Distance.l2)
// after
TurboQuantVectorDb(embedder=e, distance=Distance.cosine)
Defensive patterns

Strategy: validation

Validate before calling

from agno.vectordb.distance import Distance
if distance not in (Distance.cosine, Distance.max_inner_product):
    distance = Distance.cosine

Try / catch

try:
    db = TurboQuantVectorDb(embedder=e, distance=d)
except ValueError:
    db = TurboQuantVectorDb(embedder=e, distance=Distance.cosine)

Prevention

When it happens

Trigger: TurboQuantVectorDb(..., distance=Distance.l2) or any distance value other than cosine / max_inner_product.

Common situations: Reusing a distance enum copied from LanceDb/Milvus configs that default to L2; assuming euclidean distance is universally supported; porting pipelines tuned for L2-normalized-with-L2 setups.

Related errors


AI-assisted analysis of RyanCodrai/turbovec@ccab9f325e (2026-09-06). Data as JSON: /api/errors/1d563667f3b1238d. Report an issue: GitHub.