chroma-core/chroma · error · ChromaValueError

Expected metadata to be non-empty

Error message

Expected metadata to be non-empty

What it means

Thrown by validateMetadata in the Chroma JavaScript client when a metadata object is supplied but contains zero keys. Validation is skipped for undefined/null metadata, but an empty object {} is treated as malformed input and raises ChromaValueError before any network call. Express 'no metadata' as null (or omit the entry), never as {}.

Source

Thrown at clients/new-js/packages/chromadb/src/utils.ts:260

  return (
    indices.every((e) => typeof e === "number") &&
    values.every((e) => typeof e === "number")
  );
};

/**
 * Validates metadata object for correct types and non-emptiness.
 * @param metadata - Metadata object to validate
 * @throws ChromaValueError if metadata is invalid
 */
export const validateMetadata = (metadata?: Metadata) => {
  if (!metadata) {
    return;
  }

  if (Object.keys(metadata).length === 0) {
    throw new ChromaValueError("Expected metadata to be non-empty");
  }

  const validateMetadataListValue = (key: string, v: unknown[]): void => {
    if (v.length === 0) {
      throw new ChromaValueError(
        `Expected metadata list value for key '${key}' to be non-empty`,
      );
    }
    const firstType = typeof v[0];
    for (const item of v) {
      if (
        typeof item !== "string" &&
        typeof item !== "number" &&
        typeof item !== "boolean"
      ) {
        throw new ChromaValueError(
          `Expected metadata list value for key '${key}' to contain only strings, numbers, or booleans, got ${typeof item}`,
        );

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Pass null (or omit the entry) instead of {} for records with no metadata: metadatas: [null].
  2. Make sure every metadata object you pass has at least one string/number/boolean key.
  3. Sanitize before the call: metadatas.map(m => m && Object.keys(m).length ? m : null).

Example fix

// before
await collection.add({ ids: ['1'], documents: ['doc'], metadatas: [{}] });

// after
await collection.add({ ids: ['1'], documents: ['doc'], metadatas: [null] });
Defensive patterns

Strategy: validation

Validate before calling

const safeMetadatas = metadatas.map(m => (m && Object.keys(m).length === 0 ? null : m));
await collection.add({ ids, documents, metadatas: safeMetadatas });

Type guard

const isNonEmptyMetadata = (m: unknown): m is Record<string, unknown> =>
  typeof m === 'object' && m !== null && Object.keys(m).length > 0;

Try / catch

try {
  await collection.add({ ids, metadatas });
} catch (e) {
  if ((e as Error).message.includes('metadata to be non-empty')) {
    const fixed = metadatas.map(m => (m && Object.keys(m).length ? m : null));
    await collection.add({ ids, metadatas: fixed }); // retry with normalized metadata
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling collection.add() or upsert() with metadatas: [{}] (an empty object in the array). Building metadata by spreading optional fields that are all absent, e.g. {...(filters ?? {})} yielding {}. Mapping over a data source where some rows produce no metadata keys.

Common situations: Dynamic metadata built from optional user input or form fields; JSON deserialization that yields empty objects; refactoring that replaced null with {} during a TypeScript strictness cleanup.

Related errors


AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16). Data as JSON: /api/errors/8ec8e02d6e27fda6. Report an issue: GitHub.