mem0ai/mem0 · error · Error
Invalid filter key '${key}': only letters, digits, and under
Error message
Invalid filter key '${key}': only letters, digits, and underscores are allowed. What it means
When building SQL WHERE clauses from SearchFilters in the pgvector store, each filter key (the payload field name) is validated against SAFE_IDENTIFIER_RE. A filter key with characters other than letters, digits, and underscores (or one that starts with a digit or is over 128 chars) is rejected. This guards the key interpolation into SQL, since keys cannot be sent as bind parameters.
Source
Thrown at mem0-ts/src/oss/src/vector_stores/pgvector.ts:24
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 escapeFilterKey(key: string): string {
if (!SAFE_IDENTIFIER_RE.test(key)) {
throw new Error(
`Invalid filter key '${key}': only letters, digits, and underscores are allowed.`,
);
}
return key;
}
interface FilterResult {
conditions: string[];
values: any[];
paramIndex: number;
}
const OPERATOR_SQL_MAP: Record<string, { template: string; numeric: boolean }> =
{
eq: { template: "payload->>'%KEY%' = $%IDX%", numeric: false },
ne: { template: "payload->>'%KEY%' != $%IDX%", numeric: false },
gt: { template: "(payload->>'%KEY%')::numeric > $%IDX%", numeric: true },
gte: { template: "(payload->>'%KEY%')::numeric >= $%IDX%", numeric: true },View on GitHub (pinned to 001c235229)
Solutions
- Rename the metadata key to snake_case/alphanumeric (letters, digits, underscore, starting with a letter or underscore) both in stored payloads and in the search filters
- Re-ingest the memories with normalized metadata keys, then filter on the new keys
- If keys come from external schemas, sanitize them at write time with a shared normalizeKey() function so reads and writes agree
Example fix
// before
const results = await memory.search('q', { filters: { 'user-id': 'u1' } });
// after
const results = await memory.search('q', { filters: { user_id: 'u1' } }); Defensive patterns
Strategy: validation
Validate before calling
const SAFE_IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]{0,127}$/;
function normalizeFilters(filters: Record<string, any>) {
const out: Record<string, any> = {};
for (const [k, v] of Object.entries(filters)) {
const key = k.replace(/[^a-zA-Z0-9_]/g, '_');
if (!/^[a-zA-Z_]/.test(key)) throw new Error(`Filter key '${k}' cannot be normalized safely`);
out[key] = v;
}
return out;
} Type guard
const isSafeFilterKey = (k: string): boolean =>
/^[a-zA-Z_][a-zA-Z0-9_]{0,127}$/.test(k); Try / catch
try { await memory.search(q, { filters }); } catch (e) { if (e instanceof Error && e.message.includes('Invalid filter key')) { /* rename key, re-run */ } throw e; } Prevention
- Enforce a metadata key policy (snake_case identifiers) at memory add() time, not just at search time
- Add a lint/unit test asserting every metadata key you write passes the identifier regex
- Keep filter keys and stored payload keys in one shared constant/enum
When it happens
Trigger: Calling search/get with filters whose keys contain dots, hyphens, spaces, or start with a digit, e.g. { 'meta.type': 'fact' }, { 'user-id': 'u1' }, { '2024data': 'x' }, or keys built from arbitrary metadata field names written at add() time.
Common situations: Storing metadata keys copied from JSON APIs (dots in field names), using camelCase keys with special prefixes, or filtering on keys like 'run_id#2'. Often surfaces after data was ingested with arbitrary metadata keys.
Related errors
- Invalid ${label} '${name}': only letters, digits, and unders
- Unsupported filter operator: ${op}
- Invalid ${label} '${name}': only letters, digits, and unders
- Invalid ${label} '${name}': only letters, digits, and unders
- Databricks vector store: topK must be a positive integer, go
AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15).
Data as JSON: /api/errors/ae769517602409ea.
Report an issue: GitHub.