n8n-io/n8n · error
Filter operator "${operator}" on key "${key}" requires a non
Error message
Filter operator "${operator}" on key "${key}" requires a non-empty array value. What it means
The Supabase vector-store adapter builds PostgREST containment (`cs`) logic strings for the `in` and `nin` metadata filter operators. Those operators mean 'metadata contains any of these values', which is only meaningful for a non-empty set, so assertNonEmptyArray rejects undefined/null/scalar/[] values before they produce a malformed or vacuous query. It is a hard precondition on the filter shape, not a runtime/network failure.
Source
Thrown at packages/@n8n/agents/src/vector-stores/supabase.ts:247
assertNonEmptyArray(operator, key, value);
return `and(${value.map((candidate) => `metadata.not.cs.${quoteOrValue(containmentJson(key, candidate))}`).join(',')})`;
}
default:
throw new Error(`Unsupported filter operator: "${String(operator)}"`);
}
}
function containmentJson(key: string, value: unknown): string {
return JSON.stringify({ [key]: value });
}
function assertNonEmptyArray(
operator: string,
key: string,
value: unknown,
): asserts value is Array<string | number> {
if (!Array.isArray(value) || value.length === 0) {
throw new Error(
`Filter operator "${operator}" on key "${key}" requires a non-empty array value.`,
);
}
}
/** PostgREST logic-string values containing reserved characters must be double-quoted. */
function quoteOrValue(value: string): string {
return `"${value.replaceAll('\\', '\\\\').replaceAll('"', '\\"')}"`;
}
View on GitHub (pinned to 5ac6606e81)
Solutions
- Pass an array with at least one element: { key: 'tag', operator: 'in', value: ['red','blue'] }.
- If value is dynamic, validate before calling: skip the filter, or fall back to `eq`, when the array is empty — do not pass `value ?? []` to `in`/`nin`.
- Coerce single scalars into one-element arrays at the boundary that builds the filter.
Example fix
// before
{ key: 'tag', operator: 'in', value: maybeTags } // maybeTags may be undefined
// after
const tags = Array.isArray(maybeTags) && maybeTags.length
? maybeTags
: null;
const filter = tags ? { key: 'tag', operator: 'in', value: tags } : undefined; Defensive patterns
Strategy: validation
Validate before calling
function isNonEmptyStringArray(v: unknown): v is Array<string | number> {
return Array.isArray(v) && v.length > 0 && v.every((x) => typeof x === 'string' || typeof x === 'number');
}
// before calling the vector store:
for (const c of filter.conditions) {
if ((c.operator === 'in' || c.operator === 'nin') && !isNonEmptyStringArray(c.value)) {
throw new Error(`filter '${c.key}' needs a non-empty array`);
}
} Type guard
function isNonEmptyArray(v: unknown): v is Array<string | number> {
return Array.isArray(v) && v.length > 0;
} Prevention
- Centralize filter construction in one builder that enforces the in/nin-requires-array rule.
- At the AI-tool schema layer, mark list-typed params as required and minItems 1.
- Unit-test the vector-store filter path with undefined/empty/array inputs.
When it happens
Trigger: Calling similarity search on the Supabase vector store with a filter condition whose operator is `in` or `nin` and whose value is undefined, null, a string, a number, or an empty array `[]` (see the `in`/`nin` cases in toAndLogicTerm/toOrLogicTerm at supabase.ts:225/229/204, which both call assertNonEmptyArray before reducing over `value`).
Common situations: An upstream expression evaluates to undefined and is passed straight into the filter; the AI agent/LLM emits a single scalar instead of a list for a list-typed tool argument; a workflow maps a missing JSON field into value; the caller reuses an `eq`-style single value with the `in` operator.
Related errors
- Invalid filter operator "${operator}" for key "${key}". Supp
- Filter operator "${operator}" on key "${key}" requires a non
- Filter operator "${operator}" on key "${key}" requires array
- Filter operator "${operator}" on key "${key}" requires a str
- filterableKeys must contain at least one key
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/b32d600f748d394c.
Report an issue: GitHub.