{"record":{"id":"1333d194a9d988a8","repo":"n8n-io/n8n","slug":"metadata-value-for-key-key-is-unsupported-pi","errorCode":null,"errorMessage":"Metadata value for key \"${key}\" is unsupported: Pinecone only supports string, number, boolean, and string-array metadata values.","messagePattern":"Metadata value for key \"(.+?)\" is unsupported: Pinecone only supports string, number, boolean, and string-array metadata values\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/@n8n/agents/src/vector-stores/pinecone.ts","lineNumber":173,"sourceCode":"\tconst result: RecordMetadata = { [CONTENT_KEY]: content };\n\tfor (const [key, value] of Object.entries(metadata)) {\n\t\tassertValidMetadataValue(key, value);\n\t\tresult[key] = value;\n\t}\n\treturn result;\n}\n\n/** Pinecone metadata values are flat: string, number, boolean, or an array of strings — no nested objects or null. */\nfunction assertValidMetadataValue(\n\tkey: string,\n\tvalue: JSONValue | undefined,\n): asserts value is string | number | boolean | string[] {\n\tif (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n\t\treturn;\n\t}\n\tif (Array.isArray(value) && value.every((item) => typeof item === 'string')) return;\n\n\tthrow new Error(\n\t\t`Metadata value for key \"${key}\" is unsupported: Pinecone only supports string, number, boolean, and string-array metadata values.`,\n\t);\n}\n\nfunction toQueryResult(match: ScoredPineconeRecord): VectorQueryResult {\n\tconst { [CONTENT_KEY]: content, ...metadata } = (match.metadata ?? {}) as JSONObject;\n\treturn {\n\t\tid: String(match.id),\n\t\tcontent: typeof content === 'string' ? content : '',\n\t\tmetadata,\n\t\tscore: match.score ?? 0,\n\t};\n}\n\n/** Negations are compensated with `$exists: false` so missing-key rows match, like the other backends. */\nfunction buildPineconeFilter(filter: VectorFilter): object {\n\tconst terms = filter.conditions.map(buildCondition);\n\treturn filter.combineWith === 'or' ? { $or: terms } : { $and: terms };","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/agents/src/vector-stores/pinecone.ts#L155-L191","documentation":"Thrown by assertValidMetadataValue while building Pinecone metadata. Pinecone metadata is flat: each value must be a string, number, boolean, or an array of strings. Null, nested objects, arrays of numbers/objects, and mixed arrays are rejected up front so Pinecone never returns a 400. The offending key is named in the message.","triggerScenarios":"Upserting metadata like `{ user: null }`, `{ address: { city: 'NY' } }`, `{ tags: [1, 2, 3] }` (number array), `{ mixed: ['a', 1] }`, or `{ created: new Date() }` (object). Any nested or null value triggers it.","commonSituations":"Passing rich JSON objects from an upstream system into metadata without flattening; storing Date objects (serialize to ISO strings first); null from optional JSON fields; number arrays from numeric tag systems.","solutions":["Flatten nested objects into top-level scalar keys (e.g. `address.city` -> string value).","Convert null to a sentinel string or omit the key; serialize Dates to ISO strings.","For arrays, ensure every element is a string (map numbers to String(...)).","Strip or transform unsupported values in your ETL before addDocuments."],"exampleFix":"// before\nawait store.addDocuments([{\n  content: 'doc',\n  metadata: {\n    address: { city: 'NY' },   // nested object\n    tags: [1, 2, 3],            // number array\n    note: null,                 // null\n  },\n}]);\n\n// after\nawait store.addDocuments([{\n  content: 'doc',\n  metadata: {\n    city: 'NY',\n    tags: ['1', '2', '3'],\n  },\n}]);","handlingStrategy":"validation","validationCode":"type PineconeValue = string | number | boolean | string[];\n\nfunction toPineconeSafeMetadata(m: Record<string, unknown>): Record<string, PineconeValue> {\n  const out: Record<string, PineconeValue> = {};\n  for (const [k, v] of Object.entries(m)) {\n    if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') out[k] = v;\n    else if (Array.isArray(v) && v.every((x) => typeof x === 'string')) out[k] = v as string[];\n    else if (v === null) continue; // drop nulls\n    else if (v instanceof Date) out[k] = v.toISOString();\n    else out[k] = JSON.stringify(v); // flatten objects/other arrays to a string\n  }\n  return out;\n}\n\nawait store.addDocuments(docs.map((d) => ({ ...d, metadata: toPineconeSafeMetadata(d.metadata ?? {}) })));","typeGuard":"function isPineconeValue(v: unknown): v is PineconeValue {\n  return (\n    typeof v === 'string' ||\n    typeof v === 'number' ||\n    typeof v === 'boolean' ||\n    (Array.isArray(v) && v.every((x) => typeof x === 'string'))\n  );\n}\n\nconst safe = Object.fromEntries(Object.entries(metadata).filter(([, v]) => isPineconeValue(v)));","tryCatchPattern":"try {\n  await store.addDocuments(docs);\n} catch (err) {\n  if (err instanceof Error && /Metadata value for key/.test(err.message)) {\n    // re-sanitize metadata and retry once\n    docs = docs.map((d) => ({ ...d, metadata: toPineconeSafeMetadata(d.metadata ?? {}) }));\n    await store.addDocuments(docs);\n  } else throw err;\n}","preventionTips":["Flatten nested objects to scalar keys; serialize Dates to ISO strings; drop or stringify nulls.","For arrays, ensure every element is a string (map numbers through String).","Run a metadata-shape validator in your ingest pipeline so bad shapes never reach the store."],"tags":["pinecone","metadata","validation","vector-store"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}