chroma-core/chroma · error · ValueError

All weights must be non-negative

Error message

All weights must be non-negative

What it means

Weights in Chroma's Rrf scale each strategy's contribution weight_i / (k + rank_i), and negative weights would invert a strategy's ranking order rather than weight it — so Rrf.to_dict() rejects any weight < 0 with this ValueError at serialization/query time. Zero weights are allowed (they disable a strategy) unless normalize=True makes the total zero.

Source

Thrown at chromadb/execution/expression/operator.py:1215

        """Convert RRF to a composition of existing expression operators.

        Builds: -sum(weight_i / (k + rank_i)) for each rank
        Using Python's overloaded operators for cleaner code.
        """
        # Validate RRF parameters
        if not self.ranks:
            raise ValueError("RRF requires at least one rank")
        if self.k <= 0:
            raise ValueError(f"k must be positive, got {self.k}")

        # Validate weights if provided
        if self.weights is not None:
            if len(self.weights) != len(self.ranks):
                raise ValueError(
                    f"Number of weights ({len(self.weights)}) must match number of ranks ({len(self.ranks)})"
                )
            if any(w < 0.0 for w in self.weights):
                raise ValueError("All weights must be non-negative")

        # Populate weights with 1.0 if not provided
        weights = self.weights if self.weights else [1.0] * len(self.ranks)

        # Normalize weights if requested
        if self.normalize:
            weight_sum = sum(weights)
            if weight_sum == 0:
                raise ValueError("Sum of weights must be positive when normalize=True")
            weights = [w / weight_sum for w in weights]

        # Zip weights with ranks and build terms: weight / (k + rank)
        terms = [w / (self.k + rank) for w, rank in zip(weights, self.ranks)]

        # Sum all terms - guaranteed to have at least one
        rrf_sum: Rank = terms[0]
        for term in terms[1:]:
            rrf_sum = rrf_sum + term

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Use non-negative weights; to demote a strategy, lower its weight toward 0.0 instead of negating it
  2. If weights are computed, clamp: weights = [max(0.0, w) for w in weights]
  3. Validate all(w >= 0 for w in weights) before constructing/serializing Rrf and fail with your own message
  4. Re-check the intent: inverting a ranking is not achievable via negative RRF weight; use a different rank expression if that is the goal

Example fix

# before
rrf = Rrf(ranks=ranks, weights=[-0.5, 2.0], k=60)

# after
rrf = Rrf(ranks=ranks, weights=[0.5, 2.0], k=60)
Defensive patterns

Strategy: validation

Validate before calling

if any(w < 0 for w in weights):
    raise ValueError(f"RRF weights must be non-negative: {weights}")
rrf = Rrf(ranks=ranks, weights=weights, k=60)

Type guard

def non_negative_weights(weights) -> bool:
    return all(isinstance(w, (int, float)) and w >= 0 for w in weights)

Try / catch

try:
    plan = rrf.to_dict()
except ValueError as e:
    raise ValueError(f"invalid RRF weights {rrf.weights}: {e}") from e

Prevention

When it happens

Trigger: Rrf(ranks=[...], weights=[-1.0, 2.0], ...) then .to_dict() or query execution; commonly a sign error in tuning code, or weights computed as a difference that can go negative.

Common situations: See trigger scenarios.

Related errors


AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16). Data as JSON: /api/errors/efa6f19f57b39a39. Report an issue: GitHub.