n8n-io/n8n · error · Error

Filter operator "${operator}" on key "${key}" requires a str

Error message

Filter operator "${operator}" on key "${key}" requires a string, number, or boolean value.

What it means

For the scalar operators 'eq' and 'ne', assertValidCondition requires the value to be a string, number, or boolean. Arrays, objects, null, and undefined are rejected because scalar equality against non-scalars has no consistent meaning across vector store backends. This is the final fallthrough check after the in/nin branch returns.

Source

Thrown at packages/@n8n/agents/src/sdk/vector-store-filter.ts:64

	}

	if (operator === 'in' || operator === 'nin') {
		if (!Array.isArray(value) || value.length === 0) {
			throw new Error(
				`Filter operator "${operator}" on key "${key}" requires a non-empty array value.`,
			);
		}
		if (value.some((v) => typeof v !== 'string' && typeof v !== 'number')) {
			throw new Error(
				`Filter operator "${operator}" on key "${key}" requires array elements to be strings or numbers.`,
			);
		}
		return;
	}

	// eq, ne
	if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') {
		throw new Error(
			`Filter operator "${operator}" on key "${key}" requires a string, number, or boolean value.`,
		);
	}
}

function isNonEmptyArray(arr: string[]): arr is [string, ...string[]] {
	return arr.length > 0;
}

/** Builds the zod schema for the model-facing `filter` tool input, scoped to `keys` (key -> description). */
export function buildFilterInputSchema(keys: Record<string, string>) {
	const keyNames = Object.keys(keys);
	if (!isNonEmptyArray(keyNames)) {
		throw new Error('filterableKeys must contain at least one key');
	}

	const keyDescriptions = keyNames.map((key) => `- ${key}: ${keys[key]}`).join('\n');

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Pass a single primitive: value: 'x', value: 42, or value: true for 'eq'/'ne'.
  2. If you have an array, switch the operator to 'in'/'nin' instead of 'eq' with an array value.
  3. Reduce objects to their scalar key before building the condition: value: obj.id.

Example fix

// before
store.search('q', {
  filter: { conditions: [{ key: 'tag', operator: 'eq', value: ['x'] }], combineWith: 'and' },
}); // throws

// after — single scalar
store.search('q', {
  filter: { conditions: [{ key: 'tag', operator: 'eq', value: 'x' }], combineWith: 'and' },
});
Defensive patterns

Strategy: type-guard

Validate before calling

function eqCondition(key: string, value: unknown) {
  if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') {
    throw new Error(`'eq' filter on ${key} requires a string, number, or boolean`);
  }
  return { key, operator: 'eq' as const, value };
}

Type guard

function isScalarValue(v: unknown): v is string | number | boolean {
  return typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean';
}

Prevention

When it happens

Trigger: Calling search with filter: { conditions: [{ key: 'tag', operator: 'eq', value: ['x'] }] } (array for scalar op), value: { id: 1 } (object), or value: null. Also hit by value: undefined when a field is missing.

Common situations: Wrapping a single value in an array by mistake; passing an object that should be reduced to one of its scalar fields; null leaking from optional form fields; using 'eq' where 'in' was intended for a set.

Related errors


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