{"record":{"id":"dc6b06f652de0c63","repo":"mem0ai/mem0","slug":"invalid-label-name-only-letters-digits","errorCode":null,"errorMessage":"Invalid ${label} '${name}': only letters, digits, and underscores are allowed, must start with a letter or underscore, and be at most 128 characters.","messagePattern":"Invalid (.+?) '(.+?)': only letters, digits, and underscores are allowed, must start with a letter or underscore, and be at most 128 characters\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mem0-ts/src/oss/src/vector_stores/azure_mysql.ts","lineNumber":13,"sourceCode":"import type { Pool, RowDataPacket } from \"mysql2/promise\";\nimport { VectorStore } from \"./base\";\nimport { SearchFilters, VectorStoreConfig, VectorStoreResult } from \"../types\";\nimport { loadPeer } from \"../utils/load_peer\";\n\nconst SAFE_IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]{0,127}$/;\n\nfunction validateIdentifier(\n  name: string,\n  label: string = \"identifier\",\n): string {\n  if (!SAFE_IDENTIFIER_RE.test(name)) {\n    throw new Error(\n      `Invalid ${label} '${name}': only letters, digits, and underscores are allowed, ` +\n        `must start with a letter or underscore, and be at most 128 characters.`,\n    );\n  }\n  return name;\n}\n\nfunction cosineSimilarity(a: number[], b: number[]): number {\n  let dot = 0;\n  let normA = 0;\n  let normB = 0;\n  for (let i = 0; i < a.length; i++) {\n    dot += a[i] * b[i];\n    normA += a[i] * a[i];\n    normB += b[i] * b[i];\n  }\n  const denom = Math.sqrt(normA) * Math.sqrt(normB);\n  return denom === 0 ? 0 : dot / denom;","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/mem0ai/mem0/blob/001c235229be8795e3834520467bd0d661ed8f34/mem0-ts/src/oss/src/vector_stores/azure_mysql.ts#L1-L31","documentation":"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.","triggerScenarios":"vectorStore config collectionName: 'mem0-memories' (dash), database: 'my.db' (dot), table: '2024memories' (leading digit), or a name longer than 128 characters.","commonSituations":"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.","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."],"exampleFix":"// before\ncollectionName: 'team-alpha-memories'\n// after\ncollectionName: 'team_alpha_memories'","handlingStrategy":"validation","validationCode":"const SAFE_ID = /^[a-zA-Z_][a-zA-Z0-9_]{0,127}$/;\nfunction safeMysqlIdentifier(raw: string): string {\n  const cleaned = raw.replace(/[^a-zA-Z0-9_]/g, '_').replace(/^([0-9])/, '_$1');\n  return cleaned.slice(0, 128);\n}\nfunction assertIdentifier(name: string) { if (!SAFE_ID.test(name)) throw new Error(`Unsafe MySQL identifier: ${name}`); }","typeGuard":"const isSafeMysqlIdentifier = (s: string): boolean => /^[a-zA-Z_][a-zA-Z0-9_]{0,127}$/.test(s);","tryCatchPattern":null,"preventionTips":["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."],"tags":["azure","mysql","sql-injection","validation","identifier"],"backgroundTag":null,"analyzedSha":"001c235229be8795e3834520467bd0d661ed8f34","analyzedAt":"2026-08-15T01:55:42.685Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}