redis/redis-py · error · DataError

filters cannot be an empty collection; pass None to query…

Error message

filters cannot be an empty collection; pass None to query all indexed series.

What it means

Raised by _append_filter_expressions (used by TS.QUERYLABELS) when filters is an explicitly empty collection. None means 'query all indexed series' (FILTER omitted); an empty list is treated as a likely caller bug because silently widening to all series would be surprising.

Solutions

  1. Pass None (or omit filters) to query all indexed series.
  2. Pass a non-empty list of filter expressions.
  3. Guard dynamic filters: filters = filter_list or None.

Example fix

// before
client.ts().querylabels(filters=[])
// after
client.ts().querylabels(filters=None)
# or
client.ts().querylabels(filters=filter_list or None)
Defensive patterns

Strategy: validation

Validate before calling

filters = filters if filters else None
client.ts().querylabels(filters=filters)

Try / catch

from redis.exceptions import DataError
try:
    client.ts().querylabels(filters=filters)
except DataError:
    client.ts().querylabels(filters=None)

Prevention

When it happens

Trigger: Calling client.ts().querylabels(filters=[]) or querylabels(filters=iter([])). Passing a list that resolved to empty.

Common situations: Building filters from user input that produced no expressions. Mistakenly passing an empty list to mean 'no filter'.

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/791f15a0030738fc. Report an issue: GitHub.

Appendix: source

Thrown at redis/commands/timeseries/commands.py:1926

    @staticmethod
    def _append_filter_expressions(
        params: list[EncodableT], filters: Iterable[str] | None
    ):
        """Append the optional FILTER clause for TS.QUERYLABELS.

        ``None`` omits ``FILTER`` entirely (the documented all-series query);
        an explicitly empty collection is a local usage error, since silently
        widening to all series would be surprising. Any iterable is accepted and
        materialized once so single-pass iterators are handled correctly.
        Expressions are passed through verbatim, without parsing, reordering, or
        normalizing.
        """
        if filters is None:
            return
        filters = list(filters)
        if not filters:
            raise DataError(
                "filters cannot be an empty collection; pass None to query "
                "all indexed series."
            )
        params.append("FILTER")
        params.extend(filters)

    @staticmethod
    def _append_uncompressed(params: list[EncodableT], uncompressed: bool | None):
        """Append UNCOMPRESSED tag to params."""
        if uncompressed:
            params.extend(["ENCODING", "UNCOMPRESSED"])

    @staticmethod
    def _append_with_labels(
        params: list[EncodableT],
        with_labels: bool | None,
        select_labels: list[str] | None,
    ):

View on GitHub (pinned to 6a6b581b48)