chroma-core/chroma · error · TypeError

Limit offset must be an integer, got {type(offset).__name__}

Error message

Limit offset must be an integer, got {type(offset).__name__}

What it means

Inside Limit.from_dict, the 'offset' field must be a Python int; floats and numeric strings fail isinstance(offset, int) and raise TypeError even when they look numeric (10.5, '10'). The check runs on data.get('offset', 0), so a bad value anywhere in the dict is caught before Limit is built.

Source

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

        if self.limit is not None:
            result["limit"] = self.limit
        return result

    @staticmethod
    def from_dict(data: Dict[str, Any]) -> "Limit":
        """Create Limit from dictionary.

        Examples:
        - {"offset": 10} -> Limit(offset=10)
        - {"offset": 10, "limit": 20} -> Limit(offset=10, limit=20)
        - {"limit": 20} -> Limit(offset=0, limit=20)
        """
        if not isinstance(data, dict):
            raise TypeError(f"Expected dict for Limit, got {type(data).__name__}")

        offset = data.get("offset", 0)
        if not isinstance(offset, int):
            raise TypeError(
                f"Limit offset must be an integer, got {type(offset).__name__}"
            )
        if offset < 0:
            raise ValueError(f"Limit offset must be non-negative, got {offset}")

        limit = data.get("limit")
        if limit is not None:
            if not isinstance(limit, int):
                raise TypeError(
                    f"Limit limit must be an integer, got {type(limit).__name__}"
                )
            if limit <= 0:
                raise ValueError(f"Limit limit must be positive, got {limit}")

        # Check for unexpected keys
        allowed_keys = {"offset", "limit"}
        unexpected_keys = set(data.keys()) - allowed_keys
        if unexpected_keys:

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Send a plain int: {'offset': 10}.
  2. Coerce known-clean values before parsing: {'offset': int(offset)} (for floats, only when value.is_integer()).
  3. Declare offset as an integer field in your config/pydantic schema so it arrives typed.

Example fix

# before
Search(limit={'offset': '10', 'limit': 20})   # -> TypeError: got str

# after
Search(limit={'offset': 10, 'limit': 20})
# or, for untrusted input
Search(limit={'offset': int(offset_value), 'limit': 20})
Defensive patterns

Strategy: validation

Validate before calling

def normalize_offset(data: dict) -> dict:
    off = data.get('offset', 0)
    if isinstance(off, bool):
        raise TypeError('offset must be an int, not bool')
    if isinstance(off, float) and off.is_integer():
        return {**data, 'offset': int(off)}
    if isinstance(off, str) and off.lstrip('-').isdigit():
        return {**data, 'offset': int(off)}
    return data

Search(limit=normalize_offset(limit_cfg))

Type guard

def has_valid_offset(data) -> bool:
    off = data.get('offset', 0) if isinstance(data, dict) else None
    return isinstance(off, int) and not isinstance(off, bool)

Prevention

When it happens

Trigger: Limit.from_dict({'offset': 10.5}); Search(limit={'offset': '10'}); pagination math that mixes in a float, e.g. {'offset': int(size * (page - 1.0))} before the cast.

Common situations: Computed offsets using float arithmetic; YAML values parsed as strings ('10'); strict JSON decoders that return 10.0 for every number; form fields arriving as strings.

Related errors


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