mem0ai/mem0 · error · ValueError

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

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

ValueError from the module-level _validate_identifier helper in cassandra.py, used for keyspace and table names before any CQL is executed. It enforces ^[a-zA-Z_][a-zA-Z0-9_]{0,127}$: must start with a letter or underscore, only letters/digits/underscores after that, and at most 128 characters. This blocks CQL injection and invalid identifiers before they reach the cluster.

Source

Thrown at mem0/vector_stores/cassandra.py:28

try:
    from cassandra.auth import PlainTextAuthProvider
    from cassandra.cluster import Cluster
except ImportError:
    raise ImportError(
        "Apache Cassandra vector store requires cassandra-driver. "
        "Please install it using 'pip install cassandra-driver'"
    )

from mem0.vector_stores.base import VectorStoreBase

logger = logging.getLogger(__name__)

_SAFE_IDENTIFIER_RE = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]{0,127}$')


def _validate_identifier(name: str, label: str = "identifier") -> str:
    if not _SAFE_IDENTIFIER_RE.match(name):
        raise ValueError(
            f"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


class OutputData(BaseModel):
    id: Optional[str]
    score: Optional[float]
    payload: Optional[dict]


class CassandraDB(VectorStoreBase):
    def __init__(
        self,
        contact_points: List[str],
        port: int = 9042,
        username: Optional[str] = None,

View on GitHub (pinned to 001c235229)

Solutions

  1. Rename the keyspace/collection to match the identifier rule: letters, digits, underscores only, starting with a letter or underscore, <=128 chars.
  2. If the name is dynamic, sanitize it: re.sub(r'[^A-Za-z0-9_]', '_', name) and truncate to 128.
  3. Map unfriendly external identifiers to safe internal ones (lookup table or hash suffix) instead of passing them through.

Example fix

# before
CassandraDB(keyspace="my-keys", table="mem0", ...)  # ValueError

# after
CassandraDB(keyspace="my_keys", table="mem0", ...)
Defensive patterns

Strategy: validation

Validate before calling

import re
_IDENT = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]{0,127}$")

def safe_cassandra_name(name: str, fallback: str = "mem0") -> str:
    if not isinstance(name, str) or not _IDENT.match(name):
        cleaned = re.sub(r"[^A-Za-z0-9_]", "_", str(name))[:120]
        cleaned = re.sub(r"^[0-9]+", "", cleaned) or fallback
        return cleaned.ljust(1, "_") if not cleaned else cleaned
    return name

keyspace = safe_cassandra_name(tenant_id)

Type guard

def is_safe_cassandra_identifier(name) -> bool:
    import re
    return isinstance(name, str) and bool(re.match(r"^[a-zA-Z_][a-zA-Z0-9_]{0,127}$", name))

Prevention

When it happens

Trigger: Constructing CassandraDB with a keyspace or table name containing a hyphen (my-keys), a dot (my.keyspace), a leading digit (2keys), an empty string, or longer than 128 chars. _validate_identifier is called in __init__ for both keyspace and collection/table arguments.

Common situations: Deriving keyspace/table names from user IDs, tenant names, or hostnames that contain hyphens/dots; copying a keyspace name from a CQL shell that quotes it with double quotes (quoting is what allows special chars in CQL, but this client forbids them).

Related errors


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