mastra-ai/mastra · error
Invalid metadata key: "${key}".
Error message
Invalid metadata key: "${key}". What it means
Thread metadata passed to `listThreads` is validated against a safe-key policy: keys must match a strict pattern (start with a letter or underscore, alphanumeric/underscore only) and must not be disallowed prototype-pollution keys like `__proto__`, `constructor`, or `prototype`. This protects storage from injection/prototype-pollution via metadata keys.
Source
Thrown at packages/core/src/storage/domains/memory/base.ts:429
output[key] = sVal;
}
}
return output;
}
/**
* Validates metadata keys to prevent SQL injection attacks and prototype pollution.
* Keys must start with a letter or underscore, followed by alphanumeric characters or underscores.
* @param metadata - The metadata object to validate
* @throws Error if any key contains invalid characters or is a disallowed key
*/
protected validateMetadataKeys(metadata: Record<string, unknown> | undefined): void {
if (!metadata) return;
for (const key of Object.keys(metadata)) {
// First check for disallowed prototype pollution keys
if (DISALLOWED_METADATA_KEYS.has(key)) {
throw new Error(`Invalid metadata key: "${key}".`);
}
// Then check pattern
if (!SAFE_METADATA_KEY_PATTERN.test(key)) {
throw new Error(
`Invalid metadata key: "${key}". Keys must start with a letter or underscore and contain only alphanumeric characters and underscores.`,
);
}
// Also limit key length to prevent potential issues
if (key.length > MAX_METADATA_KEY_LENGTH) {
throw new Error(`Metadata key "${key}" exceeds maximum length of ${MAX_METADATA_KEY_LENGTH} characters.`);
}
}
}
/**
* Validates pagination parameters and returns safe offset.View on GitHub (pinned to 75dd419e61)
Solutions
- Rename offending metadata keys to match `^[A-Za-z_][A-Za-z0-9_]*$` (e.g. `project-id` → `project_id`).
- Remove disallowed keys (`__proto__`, `constructor`, `prototype`) from the metadata object.
- Sanitize/whitelist user-supplied metadata keys before passing them to `listThreads`.
- Update the stored thread metadata (or migration) so existing records no longer carry invalid keys if stored metadata is also validated.
Example fix
// before
await storage.listThreads({ metadata: { 'team-id': 't1', '__proto__': {} } });
// after
await storage.listThreads({ metadata: { team_id: 't1' } }); Defensive patterns
Strategy: validation
Validate before calling
const SAFE_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
const DISALLOWED = new Set(['__proto__', 'constructor', 'prototype']);
function assertSafeMetadataKeys(metadata: Record<string, unknown> | undefined): void {
for (const key of Object.keys(metadata ?? {})) {
if (DISALLOWED.has(key) || !SAFE_KEY.test(key)) {
throw new Error(`Invalid metadata key: "${key}"`);
}
}
}
assertSafeMetadataKeys(filter.metadata); Type guard
function hasSafeMetadataKeys(m: Record<string, unknown>): boolean {
const bad = new Set(['__proto__', 'constructor', 'prototype']);
return Object.keys(m).every(k => !bad.has(k) && /^[A-Za-z_][A-Za-z0-9_]*$/.test(k));
} Try / catch
try {
const threads = await storage.listThreads({ metadata: filter.metadata });
} catch (e) {
if (String((e as Error).message).startsWith('Invalid metadata key')) {
throw new BadRequestError('metadata filter keys must be alphanumeric/underscore and not reserved');
}
throw e;
} Prevention
- Enforce snake_case or camelCase metadata key conventions (no hyphens/dots).
- Never pass raw user-supplied keys into metadata filters; whitelist first.
- Add schema validation (zod etc.) on metadata key names at API boundaries.
- Reject reserved JS names (__proto__, constructor, prototype) in any metadata ingestion path.
When it happens
Trigger: Calling `listThreads({ metadata: { 'my-key': ... } })` (hyphens/dots/spaces fail the pattern) or `{ '__proto__': ..., 'constructor': ... }` (disallowed keys) with `metadata` filters on thread listing.
Common situations: Passing user-supplied filter keys straight through from an HTTP query string; using kebab-case keys like `project-id` instead of `project_id`; stale code constructing metadata with reserved JS names.
Related errors
- 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}".
- 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/9a1f724317e804a9.
Report an issue: GitHub.