redis/node-redis · error · Error

FILTER was given an empty filter expression list; omit it to

Error message

FILTER was given an empty filter expression list; omit it to query all indexed series

What it means

Thrown by parseQueryLabelsFilterArgument() (helpers.ts:337) when the caller passes an explicitly empty array as the FILTER list to TS.QUERYLABELS or TS.QUERYLABELS_VALUES. Passing `filter: []` would otherwise widen the command to query all series, which the server also rejects (a bare FILTER token with no expressions is invalid), so the client treats it as a local usage error and tells you to omit the argument entirely to query all indexed series.

Source

Thrown at packages/time-series/lib/commands/helpers.ts:338

  parser.push('SELECTED_LABELS');
  parser.pushVariadic(selectedLabels);
}

/**
 * Pushes the optional `FILTER filterExpr [filterExpr ...]` tail shared by the
 * `TS.QUERYLABELS` forms. Omitting `filter` queries all indexed series; passing
 * an explicitly empty array is a local usage error rather than a silent widen to
 * all series (the server also rejects a bare `FILTER` token). Expressions are
 * sent verbatim — not parsed, reordered, or deduplicated.
 */
export function parseQueryLabelsFilterArgument(
  parser: CommandParser,
  filter?: RedisVariadicArgument
) {
  if (filter === undefined) return;

  if (Array.isArray(filter) && filter.length === 0) {
    throw new Error('FILTER was given an empty filter expression list; omit it to query all indexed series');
  }

  parser.push('FILTER');
  parser.pushVariadic(filter);
}

export type RawLabelValue = BlobStringReply | NullReply;

export type RawLabels<T extends RawLabelValue> = ArrayReply<TuplesReply<[
  label: BlobStringReply,
  value: T
]>>;

export function transformRESP2Labels<T extends RawLabelValue>(
  labels: RawLabels<T>,
  typeMapping?: TypeMapping
): MapReply<BlobStringReply, T> {
  const unwrappedLabels = labels as unknown as UnwrapReply<typeof labels>;

View on GitHub (pinned to bb5beb5657)

Solutions

  1. Omit the filter argument entirely to query all indexed series.
  2. If your filter list is dynamic, pass `filter.length ? filter : undefined`.
  3. Guard the call site so an empty list is never passed: `if (!filters.length) return client.ts.queryLabels();`.
  4. Ensure at least one filter expression (e.g. 'name=temperature') when you intend to narrow.

Example fix

// before
await client.ts.queryLabels({ filter: [] });
// after — query all series
await client.ts.queryLabels();
// or, dynamic
await client.ts.queryLabels({ filter: filters.length ? filters : undefined });
Defensive patterns

Strategy: validation

Validate before calling

// Normalize a dynamic filter list before calling TS.QUERYLABELS / QUERYLABELS_VALUES.
function normalizeFilter(filter) {
  if (filter === undefined) return undefined;
  if (Array.isArray(filter)) {
    if (filter.length === 0) return undefined; // query all series
    return filter;
  }
  return filter; // single expression string
}
await client.ts.queryLabels({ filter: normalizeFilter(filters) });

Type guard

function isNonEmptyFilterList(f: unknown): f is string[] | string {
  if (typeof f === 'string') return f.length > 0;
  if (Array.isArray(f)) return f.length > 0 && f.every(x => typeof x === 'string');
  return false;
}

Try / catch

try {
  await client.ts.queryLabels({ filter });
} catch (e) {
  if (e instanceof Error && /empty filter expression list/.test(e.message)) {
    await client.ts.queryLabels(); // retry querying all series
  } else throw e;
}

Prevention

When it happens

Trigger: Calling client.ts.queryLabels({ filter: [] }) or queryLabelsValues({ filter: [] }) — passing an array that is non-undefined but empty.

Common situations: Dynamically building a filter list from user input that happened to be empty; defaulting an optional filter param to [] instead of undefined; programmatically concatenating filters and ending up with none.

Related errors


AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03). Data as JSON: /data/errors/8c6c29d8766f59f4.json. Report an issue: GitHub.