{"record":{"id":"6d63d1d3660ca1fe","repo":"n8n-io/n8n","slug":"filter-operator-operator-on-key-key-requ-6d63d1","errorCode":null,"errorMessage":"Filter operator \"${operator}\" on key \"${key}\" requires all array elements to be strings or all to be integers: Qdrant match does not support mixed-type or float values.","messagePattern":"Filter operator \"(.+?)\" on key \"(.+?)\" requires all array elements to be strings or all to be integers: Qdrant match does not support mixed-type or float values\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/@n8n/agents/src/vector-stores/qdrant.ts","lineNumber":177,"sourceCode":"\t\t\tif (typeof value === 'number' && !Number.isInteger(value)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Filter operator \"${operator}\" on key \"${key}\" does not support float values: Qdrant match only supports strings, integers, and booleans.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst match: Schemas['Condition'] = { key: payloadKey, match: { value } };\n\t\t\treturn operator === 'eq' ? match : { must_not: [match] };\n\t\t}\n\t\tcase 'in':\n\t\tcase 'nin': {\n\t\t\tif (!Array.isArray(value) || value.length === 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Filter operator \"${operator}\" on key \"${key}\" requires a non-empty array value.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst allStrings = value.every((v) => typeof v === 'string');\n\t\t\tconst allIntegers = value.every((v) => typeof v === 'number' && Number.isInteger(v));\n\t\t\tif (!allStrings && !allIntegers) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Filter operator \"${operator}\" on key \"${key}\" requires all array elements to be strings or all to be integers: Qdrant match does not support mixed-type or float values.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\t// eslint-disable-next-line id-denylist -- `any` is Qdrant's match-schema field name\n\t\t\tconst anyCondition: Schemas['Condition'] = { key: payloadKey, match: { any: value } };\n\t\t\treturn operator === 'in' ? anyCondition : { must_not: [anyCondition] };\n\t\t}\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported filter operator: \"${String(operator)}\"`);\n\t}\n}\n","sourceCodeStart":159,"sourceCodeEnd":189,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/agents/src/vector-stores/qdrant.ts#L159-L189","documentation":"Thrown by buildCondition in the Qdrant backend for `in`/`nin` conditions when the array is neither all-strings nor all-integers (e.g. mixed `['a', 5]`, or contains floats like `[1.5, 2.5]`, or contains booleans). Qdrant's `match.any` requires a homogeneous array of strings or integers; mixed-type or float arrays are rejected before the request. Operator and key are named.","triggerScenarios":"`{ key: 'k', operator: 'in', value: ['a', 1] }` (mixed); `{ key: 'k', operator: 'in', value: [1.1, 2.2] }` (floats); `{ key: 'k', operator: 'in', value: ['a', true] }` (string+boolean); a heterogeneous list built from user input without normalization.","commonSituations":"Unioning filter values from multiple sources with different types; numeric ids mixed with code strings; floats from computed metadata; booleans accidentally included.","solutions":["Normalize every element to the same type before building the condition — typically map all to strings (`value.map(String)`).","Split mixed-type filters into separate homogeneous `in` conditions combined with `or`.","Drop floats from in/nin arrays (Qdrant match cannot represent them); bucket them into strings if filtering is needed."],"exampleFix":"// before — mixed types\nawait store.search('q', {\n  filter: { conditions: [{ key: 'k', operator: 'in', value: ['a', 5] }] },\n});\n\n// after — homogeneous strings\nawait store.search('q', {\n  filter: { conditions: [{ key: 'k', operator: 'in', value: ['a', '5'] }] },\n});","handlingStrategy":"type-guard","validationCode":"function homogenizeQdrantInValue(key: string, value: unknown[]): (string | number)[] {\n  const allStrings = value.every((v) => typeof v === 'string');\n  const allInts = value.every((v) => typeof v === 'number' && Number.isInteger(v));\n  if (allStrings || allInts) return value as (string | number)[];\n  // Fall back: stringify every element so Qdrant match.any accepts it.\n  return value.map((v) => String(v));\n}\n\nconst c = { key, operator: 'in' as const, value: homogenizeQdrantInValue(key, rawList) };","typeGuard":"function isHomogeneousQdrantArray(v: unknown): v is (string | number)[] {\n  if (!Array.isArray(v) || v.length === 0) return false;\n  const allStrings = v.every((x) => typeof x === 'string');\n  const allInts = v.every((x) => typeof x === 'number' && Number.isInteger(x));\n  return allStrings || allInts;\n}\n\nif (!isHomogeneousQdrantArray(c.value)) c.value = c.value.map(String);","tryCatchPattern":"try {\n  await store.search('q', { filter: { conditions, combineWith: 'and' } });\n} catch (err) {\n  if (err instanceof Error && /requires all array elements to be strings/.test(err.message)) {\n    // homogenize to strings and retry once\n    conditions = conditions.map((c) =>\n      (c.operator === 'in' || c.operator === 'nin') && Array.isArray(c.value)\n        ? { ...c, value: c.value.map(String) }\n        : c,\n    );\n    await store.search('q', { filter: { conditions, combineWith: 'and' } });\n  } else throw err;\n}","preventionTips":["Normalize in/nin arrays to one type (usually all strings) before building the condition.","Never mix strings and numbers, and never include floats or booleans, in a Qdrant in/nin value.","Centralize Qdrant filter construction behind a homogenizing helper."],"tags":["qdrant","filter","validation","vector-store","type-mismatch"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}