mastra-ai/mastra · error · TypeError

Invalid metadata filter value for key "${key}". Values must

Error message

Invalid metadata filter value for key "${key}". Values must be string, finite number, boolean, or null.

What it means

Metadata filter values must be string, boolean, finite number, or null. Objects, arrays, undefined, NaN, and Infinity are rejected because storage metadata matching supports only scalar equality semantics.

Source

Thrown at packages/core/src/storage/utils.ts:124

    throw new TypeError('Metadata filter must be an object.');
  }

  const entries = Object.entries(metadata);
  for (const [key, value] of entries) {
    if (
      key.length > MAX_METADATA_KEY_LENGTH ||
      !SAFE_METADATA_KEY_PATTERN.test(key) ||
      DISALLOWED_METADATA_KEYS.has(key)
    ) {
      throw new TypeError(`Invalid metadata filter key "${key}".`);
    }
    if (
      value !== null &&
      typeof value !== 'string' &&
      typeof value !== 'boolean' &&
      !(typeof value === 'number' && Number.isFinite(value))
    ) {
      throw new TypeError(
        `Invalid metadata filter value for key "${key}". Values must be string, finite number, boolean, or null.`,
      );
    }
  }

  return entries.length > 0 ? metadata : undefined;
}

export function storageMessageMatchesMetadataFilter(
  content: unknown,
  filter: StorageMetadataFilter | undefined,
): boolean {
  if (!filter) return true;
  const parsedContent = typeof content === 'string' ? safelyParseJSON(content) : content;
  if (!parsedContent || typeof parsedContent !== 'object' || Array.isArray(parsedContent)) return false;
  const metadata = (parsedContent as { metadata?: unknown }).metadata;
  if (!metadata || typeof metadata !== 'object' || Array.isArray(metadata)) return false;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Use a scalar value: string, boolean, finite number, or null
  2. For multiple candidate values, issue multiple queries or encode as a delimited string ('a|b')
  3. Convert Dates to ISO strings: date.toISOString()
  4. Check finiteness: Number.isFinite(value) before building the filter

Example fix

// before
metadata: { createdAt: new Date(), tags: ['a','b'] }
// after
metadata: { createdAt: new Date().toISOString(), tag: 'a' }
Defensive patterns

Strategy: validation

Validate before calling

function isValidMetadataValue(v: unknown): boolean {
  return v === null || typeof v === 'string' || typeof v === 'boolean' ||
    (typeof v === 'number' && Number.isFinite(v));
}
if (!Object.values(filter).every(isValidMetadataValue)) throw new Error('Bad metadata values');

Type guard

type MetadataValue = string | number | boolean | null;
function isMetadataValue(v: unknown): v is MetadataValue {
  return v === null || typeof v === 'string' || typeof v === 'boolean' ||
    (typeof v === 'number' && Number.isFinite(v));
}

Try / catch

try {
  return await storage.listTraces({ metadata: filter });
} catch (e) {
  if (e instanceof TypeError && e.message.includes('metadata filter value')) {
    logger.warn('Falling back to unfiltered query', { filter });
    return await storage.listTraces({});
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing nested objects ({ nested: { a: 1 } }), arrays ({ tags: ['a','b'] }), undefined, NaN, or Infinity as a value for some key in the metadata filter object.

Common situations: Expecting array 'IN' semantics (values: [..]) or range objects ({$gt: 5}); passing raw Date objects; NaN leaking from computed values.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/eabd13683f9f086f. Report an issue: GitHub.