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
- Use a scalar value: string, boolean, finite number, or null
- For multiple candidate values, issue multiple queries or encode as a delimited string ('a|b')
- Convert Dates to ISO strings: date.toISOString()
- 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
- Serialize Dates/objects to strings before adding to metadata
- Guard against NaN/Infinity with Number.isFinite
- Use separate queries instead of array values for 'IN' semantics
- Type metadata maps as Record<string, MetadataValue> so TS catches bad values
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
- Invalid metadata key: "${key}".
- Invalid metadata key: "${key}". Keys must start with a lette
- Metadata key "${key}" exceeds maximum length of ${MAX_METADA
- Metadata filter must be an object.
- Invalid metadata filter key "${key}".
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/eabd13683f9f086f.
Report an issue: GitHub.