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

  1. Pass an array with at least one element: { key: 'tag', operator: 'in', value: ['red','blue'] }.
  2. 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`.
  3. 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

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


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/b32d600f748d394c. Report an issue: GitHub.