mastra-ai/mastra · error · TypeError
Metadata filter must be an object.
Error message
Metadata filter must be an object.
What it means
validateStorageMetadataFilter requires the metadata filter to be a plain object (not undefined, null, an array, or a primitive). Metadata filters are key/value maps used to filter records in storage; anything else cannot be interpreted as a filter map, so a TypeError is thrown before hitting storage.
Source
Thrown at packages/core/src/storage/utils.ts:106
return JSON.parse(input);
} catch {
return input;
}
}
// For anything else (number, boolean, etc.), return empty object
return {};
}
const SAFE_METADATA_KEY_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
const MAX_METADATA_KEY_LENGTH = 128;
const DISALLOWED_METADATA_KEYS = new Set(['__proto__', 'prototype', 'constructor']);
export function validateStorageMetadataFilter(
metadata: StorageMetadataFilter | undefined,
): StorageMetadataFilter | undefined {
if (metadata === undefined) return undefined;
if (!metadata || typeof metadata !== 'object' || Array.isArray(metadata)) {
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(View on GitHub (pinned to 75dd419e61)
Solutions
- Pass a plain object like { region: 'us', env: 'prod' }
- Convert arrays of pairs: Object.fromEntries([['region','us']])
- Parse string filters from query params with JSON.parse or your own parser before calling
- Guard: if (filter && !Array.isArray(filter)) before calling
Example fix
// before
storage.listTraces({ metadata: 'tenant=acme' });
// after
storage.listTraces({ metadata: { tenant: 'acme' } }); Defensive patterns
Strategy: validation
Validate before calling
function isPlainObject(v: unknown): v is Record<string, unknown> {
return typeof v === 'object' && v !== null && !Array.isArray(v);
}
const filter = isPlainObject(rawFilter) ? rawFilter : {}; Type guard
function isMetadataFilter(v: unknown): v is Record<string, string | number | boolean | null> {
return typeof v === 'object' && v !== null && !Array.isArray(v);
} Try / catch
try {
return await storage.listTraces({ metadata: filter });
} catch (e) {
if (e instanceof TypeError && e.message.includes('Metadata filter')) {
logger.warn('Dropping invalid metadata filter', { filter });
return await storage.listTraces({});
}
throw e;
} Prevention
- Validate/parse filters from user input (URL params, JSON) before passing them
- Never pass arrays as filters; use Object.fromEntries for pair lists
- Coerce null to undefined at the boundary if 'no filter' is intended
- Add unit tests covering filter parsing from all your input sources
When it happens
Trigger: Calling metadataFilter(null), metadataFilter([]) (an array is an object but rejected), or metadataFilter('region=us') — any non-plain-object value passed where a metadata filter is expected (e.g. in storage list/query APIs).
Common situations: Spreading optional params into a query and passing a variable that ended up null after JSON parsing; accidentally passing an array of key/value pairs instead of an object; string-encoded filters from URL query params not being parsed.
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
- Invalid metadata filter key "${key}".
- Invalid metadata filter value for key "${key}". Values must
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/563af99015d5291b.
Report an issue: GitHub.