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

  1. Flatten nested objects into top-level scalar keys (e.g. `address.city` -> string value).
  2. Convert null to a sentinel string or omit the key; serialize Dates to ISO strings.
  3. For arrays, ensure every element is a string (map numbers to String(...)).
  4. 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

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


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