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
- Rename the table/database to only letters, digits, underscores, starting with a letter or underscore, max 128 chars.
- If the name derives from external input, sanitize it (replace non-word chars with '_') before passing it in config.
- 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
- Normalize externally derived names (org slugs, tenant ids) with a sanitizer before using them as collectionName.
- Standardize on snake_case table names project-wide.
- Assert the identifier shape at config load time, not at first query.
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
- Identifier name ${name} is not valid.
- Invalid {label} '{name}': only letters, digits, and undersco
- Azure OpenAI requires both API key and endpoint
- Azure OpenAI requires both API key and endpoint
- Azure credential authentication failed: ${err}
AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15).
Data as JSON: /api/errors/dc6b06f652de0c63.
Report an issue: GitHub.