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
- Omit the filter argument entirely to query all indexed series.
- If your filter list is dynamic, pass `filter.length ? filter : undefined`.
- Guard the call site so an empty list is never passed: `if (!filters.length) return client.ts.queryLabels();`.
- 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
- Default optional filter params to undefined, never [].
- At call sites that build filters from user input, pass `filters.length ? filters : undefined`.
- Add a unit test asserting queryLabels() is never invoked with an empty array.
- Treat 'no filter' as 'omit the argument', matching the documented behavior.
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
- "arguments[${i}]" must be of type "string | Buffer", got ${t
- expirationRefreshRatio must be less than or equal to 1
- expirationRefreshRatio must be greater or equal to 0
- All statistics values must be non-negative
- HIMPORT PREPARE/DISCARD/DISCARDALL are not supported inside
AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03).
Data as JSON: /data/errors/8c6c29d8766f59f4.json.
Report an issue: GitHub.