{"record":{"id":"bad79cdf6235e82a","repo":"mem0ai/mem0","slug":"unsupported-oracle-filter-operator-s-for-field","errorCode":null,"errorMessage":"Unsupported Oracle filter operator(s) for field '${metadataKey}': ${unsupported.sort().join(\", \")}","messagePattern":"Unsupported Oracle filter operator\\(s\\) for field '(.+?)': (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mem0-ts/src/oss/src/vector_stores/oracledb.ts","lineNumber":156,"sourceCode":"\n  if (Array.isArray(value)) {\n    throw new Error(\n      `Oracle filter for field '${metadataKey}' must be a scalar or an operator object`,\n    );\n  }\n\n  const operators = Object.entries(value);\n  if (operators.length === 0) {\n    throw new Error(\n      `Operator filter for field '${metadataKey}' must not be empty`,\n    );\n  }\n\n  const unsupported = operators\n    .map(([op]) => op)\n    .filter((op) => !FIELD_OPERATORS.has(op));\n  if (unsupported.length > 0) {\n    throw new Error(\n      `Unsupported Oracle filter operator(s) for field '${metadataKey}': ${unsupported.sort().join(\", \")}`,\n    );\n  }\n\n  const predicates: string[] = [];\n  const passings: string[] = [];\n  const additionalClauses: string[] = [];\n\n  for (const [operator, operand] of operators) {\n    if (operator in COMPARISON_OPERATORS) {\n      if (!isScalar(operand)) {\n        throw new Error(\n          `Oracle filter operator '${operator}' requires a scalar value`,\n        );\n      }\n      if (operand === null) {\n        if (operator !== \"eq\" && operator !== \"ne\") {\n          throw new Error(","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/mem0ai/mem0/blob/001c235229be8795e3834520467bd0d661ed8f34/mem0-ts/src/oss/src/vector_stores/oracledb.ts#L138-L174","documentation":"Thrown while translating a MongoDB-style field filter into an Oracle JSON_EXISTS predicate. buildFieldCondition inspects the operator object for a field and rejects any operator key not in FIELD_OPERATORS (eq, ne, gt, gte, lt, lte, in, nin, contains, icontains). This guard exists because the Oracle JSON path language only supports a fixed comparison subset, so unknown operators cannot be mapped to SQL.","triggerScenarios":"Calling search()/getAll() with filters like { user_id: { $eq: 'u1', $regex: '.*' } } — '$regex' is not in FIELD_OPERATORS and triggers the error listing '$regex'. Any filter object under a field key containing operators such as $exists, $size, $all, $elemMatch, $between, or $not (field-level) will be rejected.","commonSituations":"Copying filter syntax from the MongoDB docs or from another mem0 vector store backend (e.g. Qdrant/pgvector) that supports a wider operator set; using '$in' instead of the required 'in' (no dollar prefix); writing nested operator objects where a plain value was expected.","solutions":["Rewrite the filter using only supported operators: eq, ne, gt, gte, lt, lte, in, nin, contains, icontains — without the '$' prefix.","Replace '$in' with 'in' and '$nin' with 'nin'; the Oracle adapter uses unprefixed operator names.","Replace unsupported operators with supported equivalents: $regex → contains/icontains on strings, $exists → the '*' value (field presence check), $gt/$gte/$lt/$lte → gt/gte/lt/lte.","Run search() without filters and post-filter in application code if the predicate cannot be expressed with the supported set."],"exampleFix":"// before\nawait memory.search('query', { filters: { user_id: { $in: ['u1','u2'] } } });\n\n// after\nawait memory.search('query', { filters: { user_id: { in: ['u1', 'u2'] } } });","handlingStrategy":"validation","validationCode":"const FIELD_OPERATORS = new Set(['eq','ne','gt','gte','lt','lte','in','nin','contains','icontains']);\nfunction validateFieldFilters(filters: any, path = 'filters'): void {\n  if (!filters || typeof filters !== 'object') return;\n  for (const [key, value] of Object.entries(filters)) {\n    if (key.startsWith('$') || key === 'AND' || key === 'OR' || key === 'NOT') {\n      if (Array.isArray(value)) value.forEach((c, i) => validateFieldFilters(c, `${path}.${key}[${i}]`));\n      continue;\n    }\n    if (value && typeof value === 'object' && !Array.isArray(value)) {\n      const bad = Object.keys(value).filter((op) => !FIELD_OPERATORS.has(op));\n      if (bad.length) throw new RangeError(`${path}: unsupported operators ${bad.join(', ')} on field '${key}'`);\n    }\n  }\n}","typeGuard":"function isSupportedFieldFilter(v: any): boolean {\n  return v !== null && typeof v === 'object' && !Array.isArray(v) &&\n    Object.keys(v).every((op) => ['eq','ne','gt','gte','lt','lte','in','nin','contains','icontains'].includes(op));\n}","tryCatchPattern":"try { await memory.search('q', { filters }); } catch (e) { if (e instanceof Error && e.message.includes('Unsupported Oracle filter operator')) { /* rewrite or drop the offending operators, retry without them */ } else throw e; }","preventionTips":["Keep one shared filter-builder module that only emits eq/ne/gt/gte/lt/lte/in/nin/contains/icontains.","Strip '$' prefixes when porting Mongo-style filters: $in → in, $nin → nin.","Add unit tests over the filter builder asserting the supported-operator set."],"tags":["oracle","filters","vector-store","validation","typescript"],"backgroundTag":null,"analyzedSha":"001c235229be8795e3834520467bd0d661ed8f34","analyzedAt":"2026-08-15T01:55:42.685Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}