{"record":{"id":"7238f1c52617c6ba","repo":"mem0ai/mem0","slug":"invalid-filter-key-key","errorCode":null,"errorMessage":"Invalid filter key: ${key}","messagePattern":"Invalid filter key: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mem0-ts/src/oss/src/vector_stores/baidu.ts","lineNumber":266,"sourceCode":"          indexName: BM25_INDEX,\n          indexType: IndexType.InvertedIndex,\n          fields: [\"textLemmatized\"],\n          fieldAttributes: [InvertedIndexFieldAttribute.Analyzed],\n          params: {\n            analyzer: InvertedIndexAnalyzer.EnglishAnalyzer,\n            parseMode: InvertedIndexParseMode.FineMode,\n          },\n        },\n      ],\n    };\n  }\n\n  private buildFilter(filters: SearchFilters): string {\n    const conditions: string[] = [];\n\n    for (const [key, value] of Object.entries(filters)) {\n      if (!SAFE_FILTER_KEY.test(key)) {\n        throw new Error(`Invalid filter key: ${key}`);\n      }\n\n      if (typeof value === \"string\") {\n        conditions.push(`metadata[\"${key}\"] = \"${escapeFilterString(value)}\"`);\n        continue;\n      }\n\n      if (typeof value === \"number\" || typeof value === \"boolean\") {\n        conditions.push(`metadata[\"${key}\"] = ${value}`);\n        continue;\n      }\n\n      throw new Error(\n        `Filter value for ${key} must be str, int, float, or bool, got ${Array.isArray(value) ? \"array\" : typeof value}`,\n      );\n    }\n\n    return conditions.join(\" AND \");","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/mem0ai/mem0/blob/001c235229be8795e3834520467bd0d661ed8f34/mem0-ts/src/oss/src/vector_stores/baidu.ts#L248-L284","documentation":"Baidu Mochow filters are rendered into a SQL-like predicate string (metadata[\"key\"] = value), so buildFilter validates each filter key against a safe-key regex (SAFE_FILTER_KEY) before interpolation, throwing for keys that fail. This is an injection guard: keys cannot be parameterized in the filter DSL. Keys with quotes, brackets, spaces, or special characters are rejected.","triggerScenarios":"memory.search(query, { userId: 'alice' }) style filters where the key contains a dash or quote, e.g. { 'user-id': 'u1' }; filters built from raw user input keys like { \"name'; DROP\": 1 }; keys with spaces or non-ASCII.","commonSituations":"Using metadata keys with dashes or dots that other vector stores accept; forwarding arbitrary user-supplied filter keys to search(); schema drift between what you stored in metadata and what you filter on.","solutions":["Use simple alphanumeric/underscore filter keys (and store metadata under those same keys).","Sanitize or reject user-supplied filter keys before search() (map unsafe keys to safe aliases).","Never pass unvalidated external input as filter keys."],"exampleFix":"// before\nmemory.search('q', { 'user-id': 'u1' });\n// after\nmemory.search('q', { user_id: 'u1' });","handlingStrategy":"validation","validationCode":"const SAFE_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;\nfunction sanitizeFilterKeys(filters: Record<string, unknown>) {\n  const out: Record<string, unknown> = {};\n  for (const [k, v] of Object.entries(filters)) {\n    const key = SAFE_KEY.test(k) ? k : k.replace(/[^A-Za-z0-9_]/g, '_');\n    out[key] = v;\n  }\n  return out;\n}","typeGuard":"const isSafeFilterKey = (k: string): boolean => /^[A-Za-z_][A-Za-z0-9_]*$/.test(k);","tryCatchPattern":null,"preventionTips":["Restrict metadata keys used for filtering to word characters at write time.","Never forward raw user input as filter keys; allowlist the accepted keys."],"tags":["baidu","filters","sql-injection","validation","search"],"backgroundTag":null,"analyzedSha":"001c235229be8795e3834520467bd0d661ed8f34","analyzedAt":"2026-08-15T01:55:42.685Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}