mem0ai/mem0 · error · Error

Invalid ${label} '${name}': only letters, digits, and unders

Error message

Invalid ${label} '${name}': only letters, digits, and underscores are allowed, must start with a letter or underscore, and be at most 128 characters.

What it means

azure_mysql.ts validates every identifier (table name, database name) against /^[a-zA-Z_][a-zA-Z0-9_]{0,127}$/ before it is interpolated into SQL, throwing with the offending name and label. This is a SQL-injection guard: MySQL identifiers cannot be parameterized, so they must be allowlisted by shape. Names with dashes, dots, spaces, starting with a digit, or longer than 128 chars are rejected.

Source

Thrown at mem0-ts/src/oss/src/vector_stores/azure_mysql.ts:13

import type { Pool, RowDataPacket } from "mysql2/promise";
import { VectorStore } from "./base";
import { SearchFilters, VectorStoreConfig, VectorStoreResult } from "../types";
import { loadPeer } from "../utils/load_peer";

const SAFE_IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]{0,127}$/;

function validateIdentifier(
  name: string,
  label: string = "identifier",
): string {
  if (!SAFE_IDENTIFIER_RE.test(name)) {
    throw new Error(
      `Invalid ${label} '${name}': only letters, digits, and underscores are allowed, ` +
        `must start with a letter or underscore, and be at most 128 characters.`,
    );
  }
  return name;
}

function cosineSimilarity(a: number[], b: number[]): number {
  let dot = 0;
  let normA = 0;
  let normB = 0;
  for (let i = 0; i < a.length; i++) {
    dot += a[i] * b[i];
    normA += a[i] * a[i];
    normB += b[i] * b[i];
  }
  const denom = Math.sqrt(normA) * Math.sqrt(normB);
  return denom === 0 ? 0 : dot / denom;

View on GitHub (pinned to 001c235229)

Solutions

  1. Rename the table/database to only letters, digits, underscores, starting with a letter or underscore, max 128 chars.
  2. If the name derives from external input, sanitize it (replace non-word chars with '_') before passing it in config.
  3. Do not attempt to bypass the guard; it exists because identifiers are string-interpolated into SQL.

Example fix

// before
collectionName: 'team-alpha-memories'
// after
collectionName: 'team_alpha_memories'
Defensive patterns

Strategy: validation

Validate before calling

const SAFE_ID = /^[a-zA-Z_][a-zA-Z0-9_]{0,127}$/;
function safeMysqlIdentifier(raw: string): string {
  const cleaned = raw.replace(/[^a-zA-Z0-9_]/g, '_').replace(/^([0-9])/, '_$1');
  return cleaned.slice(0, 128);
}
function assertIdentifier(name: string) { if (!SAFE_ID.test(name)) throw new Error(`Unsafe MySQL identifier: ${name}`); }

Type guard

const isSafeMysqlIdentifier = (s: string): boolean => /^[a-zA-Z_][a-zA-Z0-9_]{0,127}$/.test(s);

Prevention

When it happens

Trigger: vectorStore config collectionName: 'mem0-memories' (dash), database: 'my.db' (dot), table: '2024memories' (leading digit), or a name longer than 128 characters.

Common situations: Using hyphenated names that MySQL itself permits when quoted but this store does not; copying collection names from other providers (Qdrant allows dashes); generating names from user/org ids that contain arbitrary characters.

Related errors


AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15). Data as JSON: /api/errors/dc6b06f652de0c63. Report an issue: GitHub.