mem0ai/mem0 · error · ValueError
Invalid collection_name: {v!r}. Must start with a letter or
Error message
Invalid collection_name: {v!r}. Must start with a letter or underscore and contain only letters, digits, and underscores. What it means
The Azure MySQL vector store validates collection_name (used as the table identifier) against a SQL-identifier regex: it must start with a letter or underscore and contain only letters, digits, and underscores. A failed match raises ValueError at config-parse time, before any DB connection. This exists because the value is interpolated into DDL/SQL for MySQL.
Source
Thrown at mem0/configs/vector_stores/azure_mysql.py:37
collection_name: str = Field("mem0", description="Collection/table name")
embedding_model_dims: int = Field(1536, description="Dimensions of the embedding model")
use_azure_credential: bool = Field(
False,
description="Use Azure DefaultAzureCredential for authentication instead of password"
)
ssl_ca: Optional[str] = Field(None, description="Path to SSL CA certificate")
ssl_disabled: bool = Field(False, description="Disable SSL connection (not recommended for production)")
minconn: int = Field(1, description="Minimum number of connections in the pool")
maxconn: int = Field(5, description="Maximum number of connections in the pool")
connection_pool: Optional[Any] = Field(
None,
description="Pre-configured connection pool object (overrides other connection parameters)"
)
@field_validator("collection_name")
def validate_collection_name(cls, v):
if not _VALID_SQL_IDENTIFIER.match(v):
raise ValueError(
f"Invalid collection_name: {v!r}. Must start with a letter or underscore and "
"contain only letters, digits, and underscores."
)
return v
@model_validator(mode="before")
@classmethod
def check_auth(cls, values: Dict[str, Any]) -> Dict[str, Any]:
"""Validate authentication parameters."""
# If connection_pool is provided, skip validation
if values.get("connection_pool") is not None:
return values
use_azure_credential = values.get("use_azure_credential", False)
password = values.get("password")
# Either password or Azure credential must be provided
if not use_azure_credential and not password:View on GitHub (pinned to 001c235229)
Solutions
- Rename the collection to match [A-Za-z_][A-Za-z0-9_]* — e.g. 'memories_test', 'user_42'
- Sanitize derived names: re.sub(r'[^A-Za-z0-9_]', '_', name) and prefix an underscore if it starts with a digit
- Never build collection names from untrusted raw input without this normalization
Example fix
# before
"config": {"host": H, "database": D, "collection_name": f"mem-{user_id}"}
# after
import re
name = re.sub(r"[^A-Za-z0-9_]", "_", f"mem-{user_id}")
if name[0].isdigit():
name = f"_{name}"
"config": {"host": H, "database": D, "collection_name": name} Defensive patterns
Strategy: validation
Validate before calling
import re
def safe_table_name(name: str) -> str:
n = re.sub(r"[^A-Za-z0-9_]", "_", name)
if not re.match(r"^[A-Za-z_]", n):
n = "_" + n
return n
"config": {"host": H, "database": D, "collection_name": safe_table_name(raw)} Type guard
import re
_SQL_IDENT = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
def is_valid_collection_name(v: object) -> bool:
return isinstance(v, str) and bool(_SQL_IDENT.match(v)) Try / catch
try:
Memory.from_config(config)
except ValueError as e:
if "Invalid collection_name" in str(e):
raise ConfigError("collection_name must match [A-Za-z_][A-Za-z0-9_]*") from e
raise Prevention
- Never interpolate raw user/org IDs into collection_name; normalize them first
- Note that names valid in other vector stores (dots, hyphens) are invalid here because MySQL treats it as a SQL identifier
When it happens
Trigger: Passing collection_name values like 'my-table' (hyphen), 'memories.table', '123memories' (leading digit), 'user memories' (space), or any name with quotes/semicolon — including classic SQL-injection-shaped input — in the azure_mysql vector store config.
Common situations: Deriving the table name from user IDs, org names, or free text; reusing collection names valid in other stores (qdrant/chroma allow dots and hyphens) for MySQL; MySQL doesn't allow hyphens unquoted in identifiers, hence the strict rule.
Related errors
- Baidu vector store requires a non-empty '${name}' config val
- Extra fields not allowed: {', '.join(extra_fields)}. Please
- Invalid compression_type: {values['compression_type']}. Must
- Unsupported VectorStore provider: {provider_name}
- When embeddings are enabled, all payloads must contain a 'da
AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15).
Data as JSON: /api/errors/26c14ddc4d024727.
Report an issue: GitHub.