{"record":{"id":"467a6d1f2bacb7b0","repo":"n8n-io/n8n","slug":"filter-operator-operator-on-key-key-requ-467a6d","errorCode":null,"errorMessage":"Filter operator \"${operator}\" on key \"${key}\" requires a non-empty array value.","messagePattern":"Filter operator \"(.+?)\" on key \"(.+?)\" requires a non-empty array value\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/@n8n/agents/src/vector-stores/postgres.ts","lineNumber":191,"sourceCode":"\tprivate buildConditionClause(\n\t\tcondition: FilterCondition,\n\t\tnextParam: (value: unknown) => string,\n\t): string {\n\t\tconst { key, operator, value } = condition;\n\n\t\tswitch (operator) {\n\t\t\tcase 'eq': {\n\t\t\t\tconst v = nextParam(JSON.stringify({ [key]: value }));\n\t\t\t\treturn `metadata @> ${v}::jsonb`;\n\t\t\t}\n\t\t\tcase 'ne': {\n\t\t\t\tconst v = nextParam(JSON.stringify({ [key]: value }));\n\t\t\t\treturn `NOT (metadata @> ${v}::jsonb)`;\n\t\t\t}\n\t\t\tcase 'in':\n\t\t\tcase 'nin': {\n\t\t\t\tif (!Array.isArray(value) || value.length === 0) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Filter operator \"${operator}\" on key \"${key}\" requires a non-empty array value.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// Containment per candidate (rather than `metadata->>key = ANY(text[])`) keeps\n\t\t\t\t// numeric and string metadata distinct — text extraction would otherwise make\n\t\t\t\t// the number 5 and the string \"5\" match the same filter value.\n\t\t\t\tconst anyMatch = value\n\t\t\t\t\t.map(\n\t\t\t\t\t\t(candidate) => `metadata @> ${nextParam(JSON.stringify({ [key]: candidate }))}::jsonb`,\n\t\t\t\t\t)\n\t\t\t\t\t.join(' OR ');\n\t\t\t\treturn operator === 'in' ? `(${anyMatch})` : `NOT (${anyMatch})`;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unsupported filter operator: \"${String(operator)}\"`);\n\t\t}\n\t}\n","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/agents/src/vector-stores/postgres.ts#L173-L209","documentation":"Thrown by buildConditionClause in the Postgres backend when an `in`/`nin` filter condition's value is not an array or is empty. The `in`/`nin` operators compile to per-candidate jsonb containment OR-clauses, which are meaningless for zero candidates, so the value is rejected before SQL is built. Operator and key are named in the message.","triggerScenarios":"Searching with `{ filter: { conditions: [{ key: 'status', operator: 'in', value: [] }] } }`; passing a scalar to an `in` condition; a dynamic filter whose candidate list was emptied by upstream filtering.","commonSituations":"A UI multi-select where the user clears all options but the filter is still constructed; a default empty-array filter; set difference/remove operations leaving no candidates.","solutions":["Drop the `in`/`nin` condition from `conditions` when the array is empty.","Build conditions defensively: `if (values.length) conditions.push({ key, operator: 'in', value: values })`.","If all conditions drop out, omit the filter entirely so the query is unfiltered."],"exampleFix":"// before\nawait store.search('q', {\n  filter: { conditions: [{ key: 'status', operator: 'in', value: [] }] },\n});\n\n// after\nconst conditions = [];\nif (statuses.length > 0) {\n  conditions.push({ key: 'status', operator: 'in', value: statuses });\n}\nawait store.search('q',\n  conditions.length ? { filter: { conditions, combineWith: 'and' } } : undefined,\n);","handlingStrategy":"validation","validationCode":"function dropEmptyInConditions(filter: VectorFilter): VectorFilter | undefined {\n  const conditions = filter.conditions.filter(\n    (c) => !(c.operator === 'in' || c.operator === 'nin') || (Array.isArray(c.value) && c.value.length > 0),\n  );\n  return conditions.length > 0 ? { ...filter, conditions } : undefined;\n}\n\nconst f = dropEmptyInConditions(inputFilter);\nawait store.search('q', f ? { filter: f } : undefined);","typeGuard":"function isInCondition(c: FilterCondition): c is FilterCondition & { operator: 'in' | 'nin'; value: (string | number)[] } {\n  return (c.operator === 'in' || c.operator === 'nin') && Array.isArray(c.value) && c.value.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Only add an `in`/`nin` condition when the value array has at least one element.","If filtering empties all conditions, run an unfiltered query instead.","Centralize filter construction so the empty-array rule is enforced in one place."],"tags":["postgres","filter","validation","vector-store"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}