chroma-core/chroma · error · ChromaValueError
Expected metadata value for key '${key}' to be a string, num
Error message
Expected metadata value for key '${key}' to be a string, number, boolean, SparseVector, typed array (string[], number[], boolean[]), or null What it means
The per-key loop in validateMetadata accepts only null/undefined, string, number, boolean, a SparseVector (detected by validateSparseVector), or an array (which is then list-validated). Any other value — plain objects, Dates, Maps, functions — throws ChromaValueError. This mirrors Chroma's metadata model: scalar primitives plus sparse vectors, nothing nested.
Source
Thrown at clients/new-js/packages/chromadb/src/utils.ts:305
for (const [key, v] of Object.entries(metadata)) {
if (
v === null ||
v === undefined ||
typeof v === "string" ||
typeof v === "number" ||
typeof v === "boolean"
) {
continue;
}
if (validateSparseVector(v)) {
continue;
}
if (Array.isArray(v)) {
validateMetadataListValue(key, v);
continue;
}
throw new ChromaValueError(
`Expected metadata value for key '${key}' to be a string, number, boolean, SparseVector, typed array (string[], number[], boolean[]), or null`,
);
}
};
const SPARSE_VECTOR_TYPE = "sparse_vector" as const;
type SerializedSparseVector = SparseVector & {
"#type": typeof SPARSE_VECTOR_TYPE;
};
type SerializedMetadataValue =
| boolean
| number
| string
| SerializedSparseVector
| SparseVector
| Array<boolean>View on GitHub (pinned to aecdd12c8a)
Solutions
- Flatten nested objects into dot- or underscore-separated keys, e.g. { 'source.url': 'x' }.
- Serialize Dates with toISOString() and objects with JSON.stringify() before the call.
- Keep rich structure in the document text and store only scalar primitives in metadata.
Example fix
// before
metadatas: [{ createdAt: new Date(), source: { lang: 'en' } }]
// after
metadatas: [{ createdAt: new Date().toISOString(), 'source.lang': 'en' }] Defensive patterns
Strategy: type-guard
Validate before calling
const isMetadataValue = (v) =>
v == null || ['string', 'number', 'boolean'].includes(typeof v) || Array.isArray(v);
const bad = Object.entries(meta).filter(([, v]) => !isMetadataValue(v));
if (bad.length) throw new Error(`Unsupported metadata keys: ${bad.map(([k]) => k)}`); Type guard
type MetadataValue = string | number | boolean | null | string[] | number[] | boolean[]; const isMetadataValue = (v: unknown): v is MetadataValue => v == null || ['string', 'number', 'boolean'].includes(typeof v) || Array.isArray(v);
Try / catch
try {
await collection.add({ ids, metadatas });
} catch (e) {
if ((e as Error).message.includes('SparseVector, typed array')) {
// flatten/serialize the offending values and retry
} else {
throw e;
}
} Prevention
- Flatten nested objects to dotted keys at ingestion time.
- Always call toISOString() on Dates before storing them in metadata.
- Keep a single metadata-builder function that only emits scalars and scalar lists.
When it happens
Trigger: metadatas: [{ source: { url: 'x' } }] (nested object). { createdAt: new Date() } (typeof 'object', not an array). A function or Map instance as a value.
Common situations: Trying to store structured JSON or timestamps directly in metadata; migrating from another vector DB that allowed object metadata; not realizing only string/number/boolean (plus sparse vectors) are supported.
Related errors
- Expected metadata list value for key '${key}' to contain onl
- Expected metadata list value for key '${key}' to contain onl
- Expected metadatas to be an array, but got ${typeof metadata
- Expected metadata to be non-empty
- Expected metadata list value for key '${key}' to be non-empt
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/f9064e7b68ed0d10.
Report an issue: GitHub.