mastra-ai/mastra · error

Invalid metadata key: "${key}". Keys must start with a lette

Error message

Invalid metadata key: "${key}". Keys must start with a letter or underscore and contain only alphanumeric characters and underscores.

What it means

Mastra storage validates thread metadata keys before persisting or listing threads. A key is rejected if it contains characters other than letters, digits, and underscores, or if it starts with a non-letter/non-underscore character. This guard prevents keys that could break storage backends, query syntax, or serialization.

Source

Thrown at packages/core/src/storage/domains/memory/base.ts:434

  /**
   * 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.
   * @param page - Page number (0-indexed)
   * @param perPage - Items per page (0 is allowed and returns empty results)
   * @throws Error if page is negative, perPage is negative/invalid, or offset would overflow
   */
  protected validatePagination(page: number, perPage: number): void {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Rename the offending metadata key to match /^[A-Za-z_][A-Za-z0-9_]*$/ (e.g. 'my-key' -> 'my_key').
  2. Sanitize keys programmatically before writing metadata: replace invalid characters with underscores.
  3. Drop or move invalid keys into a nested value instead of the key itself.
  4. Wrap listThreads/saveThread calls in try-catch and log/repair the offending thread data.

Example fix

// before
await memory.storage.listThreads({ metadata: { 'user-id': '42' } });
// after
await memory.storage.listThreads({ metadata: { 'user_id': '42' } });
Defensive patterns

Strategy: validation

Validate before calling

const SAFE_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
function assertValidMetadataKeys(metadata) {
  for (const key of Object.keys(metadata ?? {})) {
    if (!SAFE_KEY.test(key)) throw new Error(`Invalid metadata key: "${key}"`);
  }
}

Type guard

function hasSafeMetadataKeys(m: unknown): m is Record<string, unknown> {
  return !!m && Object.keys(m).every(k => /^[A-Za-z_][A-Za-z0-9_]*$/.test(k));
}

Try / catch

try {
  await storage.listThreads(params);
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Invalid metadata key')) {
    // sanitize metadata and retry
  } else throw e;
}

Prevention

When it happens

Trigger: Calling listThreads (or any code path that invokes validateMetadataKeys) with a thread whose metadata record contains a key like 'my-key', '123abc', 'foo.bar', or an empty string.

Common situations: Migrating data from another system that allowed hyphenated or dotted metadata keys; letting user input become metadata keys; generating keys from timestamps or IDs containing dashes or slashes.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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