{"record":{"id":"73cd970560e75543","repo":"mem0ai/mem0","slug":"oracle-filter-for-field-metadatakey-must-be-a","errorCode":null,"errorMessage":"Oracle filter for field '${metadataKey}' must be a scalar or an operator object","messagePattern":"Oracle filter for field '(.+?)' must be a scalar or an operator object","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mem0-ts/src/oss/src/vector_stores/oracledb.ts","lineNumber":140,"sourceCode":"  value: any,\n  binds: Record<string, any>,\n): string {\n  const path = jsonPath(metadataKey);\n\n  if (value === \"*\") {\n    return `JSON_EXISTS(payload, '$${path}')`;\n  }\n\n  if (isScalar(value)) {\n    if (value === null) {\n      return jsonExists(path, \"@ == null\", []);\n    }\n    const [variable, passing] = bindFilterValue(value, binds);\n    return jsonExists(path, `@ == ${variable}`, [passing]);\n  }\n\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    );","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/mem0ai/mem0/blob/001c235229be8795e3834520467bd0d661ed8f34/mem0-ts/src/oss/src/vector_stores/oracledb.ts#L122-L158","documentation":"The Oracle filter compiler accepts, per metadata field, either a scalar (equality) or an operator object ({ gte: 1, in: [...] }). A bare array is neither — it cannot become a JSON_EXISTS equality predicate nor an operator map — so it is rejected explicitly rather than guessed at (e.g. silently treated as IN).","triggerScenarios":"Passing filters = { tag: ['a','b'] } (bare array) to search/list on the Oracle store instead of the operator form { tag: { in: ['a','b'] } }.","commonSituations":"Filter syntaxes from other backends (Qdrant/mem0 Python) where a bare array implies membership; user-built filters passed straight from an API body; partial migration of filter-building code.","solutions":["Wrap arrays in an explicit operator: { tag: { in: ['a','b'] } }.","For equality use a scalar: { user_id: 'alice' }.","If you accept user filters, normalize bare arrays to { in: [...] } before calling the store."],"exampleFix":"// before\nfilters = { tag: ['a', 'b'] };\n\n// after\nfilters = { tag: { in: ['a', 'b'] } };","handlingStrategy":"validation","validationCode":"for (const [field, v] of Object.entries(filters)) {\n  if (Array.isArray(v)) filters[field] = { in: v }; // bare array -> explicit membership\n}","typeGuard":"const isScalarOrOpObject = (v: unknown): boolean =>\n  v === null || ['string','number','boolean'].includes(typeof v) ||\n  (typeof v === 'object' && v !== null && !Array.isArray(v));","tryCatchPattern":null,"preventionTips":["Use { in: [...] } for membership, never bare arrays","Use scalars for equality","Normalize filters from other backend dialects before calling Oracle"],"tags":["oracledb","filters","validation","typescript"],"backgroundTag":null,"analyzedSha":"001c235229be8795e3834520467bd0d661ed8f34","analyzedAt":"2026-08-15T01:55:42.685Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}