n8n-io/n8n · error
Metadata value for key "${key}" is unsupported: Pinecone onl
Error message
Metadata value for key "${key}" is unsupported: Pinecone only supports string, number, boolean, and string-array metadata values. What it means
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.
Source
Thrown at packages/@n8n/agents/src/vector-stores/pinecone.ts:173
const result: RecordMetadata = { [CONTENT_KEY]: content };
for (const [key, value] of Object.entries(metadata)) {
assertValidMetadataValue(key, value);
result[key] = value;
}
return result;
}
/** Pinecone metadata values are flat: string, number, boolean, or an array of strings — no nested objects or null. */
function assertValidMetadataValue(
key: string,
value: JSONValue | undefined,
): asserts value is string | number | boolean | string[] {
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
return;
}
if (Array.isArray(value) && value.every((item) => typeof item === 'string')) return;
throw new Error(
`Metadata value for key "${key}" is unsupported: Pinecone only supports string, number, boolean, and string-array metadata values.`,
);
}
function toQueryResult(match: ScoredPineconeRecord): VectorQueryResult {
const { [CONTENT_KEY]: content, ...metadata } = (match.metadata ?? {}) as JSONObject;
return {
id: String(match.id),
content: typeof content === 'string' ? content : '',
metadata,
score: match.score ?? 0,
};
}
/** Negations are compensated with `$exists: false` so missing-key rows match, like the other backends. */
function buildPineconeFilter(filter: VectorFilter): object {
const terms = filter.conditions.map(buildCondition);
return filter.combineWith === 'or' ? { $or: terms } : { $and: terms };View on GitHub (pinned to 5ac6606e81)
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.
Example fix
// before
await store.addDocuments([{
content: 'doc',
metadata: {
address: { city: 'NY' }, // nested object
tags: [1, 2, 3], // number array
note: null, // null
},
}]);
// after
await store.addDocuments([{
content: 'doc',
metadata: {
city: 'NY',
tags: ['1', '2', '3'],
},
}]); Defensive patterns
Strategy: validation
Validate before calling
type PineconeValue = string | number | boolean | string[];
function toPineconeSafeMetadata(m: Record<string, unknown>): Record<string, PineconeValue> {
const out: Record<string, PineconeValue> = {};
for (const [k, v] of Object.entries(m)) {
if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') out[k] = v;
else if (Array.isArray(v) && v.every((x) => typeof x === 'string')) out[k] = v as string[];
else if (v === null) continue; // drop nulls
else if (v instanceof Date) out[k] = v.toISOString();
else out[k] = JSON.stringify(v); // flatten objects/other arrays to a string
}
return out;
}
await store.addDocuments(docs.map((d) => ({ ...d, metadata: toPineconeSafeMetadata(d.metadata ?? {}) }))); Type guard
function isPineconeValue(v: unknown): v is PineconeValue {
return (
typeof v === 'string' ||
typeof v === 'number' ||
typeof v === 'boolean' ||
(Array.isArray(v) && v.every((x) => typeof x === 'string'))
);
}
const safe = Object.fromEntries(Object.entries(metadata).filter(([, v]) => isPineconeValue(v))); Try / catch
try {
await store.addDocuments(docs);
} catch (err) {
if (err instanceof Error && /Metadata value for key/.test(err.message)) {
// re-sanitize metadata and retry once
docs = docs.map((d) => ({ ...d, metadata: toPineconeSafeMetadata(d.metadata ?? {}) }));
await store.addDocuments(docs);
} else throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Metadata key "${CONTENT_KEY}" is reserved for the document c
- Filter operator "${operator}" on key "${key}" requires a non
- Invalid filter operator "${operator}" for key "${key}". Supp
- Filter operator "${operator}" on key "${key}" requires a non
- Filter operator "${operator}" on key "${key}" requires array
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/1333d194a9d988a8.
Report an issue: GitHub.