{"record":{"id":"119fb4b3ad8f5ce0","repo":"mem0ai/mem0","slug":"logical-filter-operator-key-requires-a-non-em","errorCode":null,"errorMessage":"Logical filter operator '${key}' requires a non-empty array","messagePattern":"Logical filter operator '(.+?)' requires a non-empty array","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mem0-ts/src/oss/src/vector_stores/oracledb.ts","lineNumber":261,"sourceCode":"\n  return clauses.length === 1 ? clauses[0] : `(${clauses.join(\" AND \")})`;\n}\n\nexport function buildFilterGroup(\n  filters: Record<string, any>,\n  binds: Record<string, any>,\n): string {\n  const entries = Object.entries(filters ?? {});\n  if (entries.length === 0) {\n    throw new Error(\"Oracle filter groups must be non-empty objects\");\n  }\n\n  const clauses: string[] = [];\n  for (const [key, value] of entries) {\n    const logicalOperator = LOGICAL_OPERATORS[key];\n    if (logicalOperator) {\n      if (!Array.isArray(value) || value.length === 0) {\n        throw new Error(\n          `Logical filter operator '${key}' requires a non-empty array`,\n        );\n      }\n      const nested = value.map((condition) =>\n        buildFilterGroup(condition, binds),\n      );\n      if (logicalOperator === \"not\") {\n        clauses.push(`NOT (${nested.join(\" OR \")})`);\n      } else {\n        clauses.push(\n          `(${nested.join(logicalOperator === \"and\" ? \" AND \" : \" OR \")})`,\n        );\n      }\n      continue;\n    }\n\n    if (key.startsWith(\"$\")) {\n      throw new Error(`Unsupported Oracle logical filter operator: ${key}`);","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/mem0ai/mem0/blob/001c235229be8795e3834520467bd0d661ed8f34/mem0-ts/src/oss/src/vector_stores/oracledb.ts#L243-L279","documentation":"Logical operators ($and/$or/$not or AND/OR/NOT) must map to a non-empty array of sub-conditions because the adapter joins the nested clauses with AND/OR inside parentheses; an empty or non-array value yields invalid SQL. The check runs before recursing into buildFilterGroup for each sub-condition.","triggerScenarios":"{ $and: [] }, { $or: 'x' }, { $not: {} } (object instead of array), or { AND: [{}] } where the inner condition object is empty — the empty inner object then fails error 266's check inside the recursion.","commonSituations":"Programmatic filter builders that always emit a top-level $and even when no conditions were collected; a client serializing a single condition as an object instead of a one-element array; copying Mongo syntax where some drivers accept $not on a field.","solutions":["Use at least one sub-condition: { $and: [{ a: 1 }] }, or omit the logical wrapper entirely for a single condition ({ a: 1 }).","In builder code, only wrap in $and/$or when conditions.length > 1.","Wrap single objects into arrays: { $or: [cond] } not { $or: cond }.","Remember $not takes an array of conditions and negates their OR-join; field-level negation uses the ne operator."],"exampleFix":"// before\nconst filters = { $and: conditions }; // conditions may be []\n\n// after\nconst filters = conditions.length > 1 ? { $and: conditions } : conditions[0];","handlingStrategy":"validation","validationCode":"function buildAnd(conditions: Record<string, any>[]): Record<string, any> | undefined {\n  const valid = conditions.filter((c) => c && Object.keys(c).length > 0);\n  if (valid.length === 0) return undefined;\n  if (valid.length === 1) return valid[0];\n  return { $and: valid };\n}","typeGuard":"const isNonEmptyConditionArray = (v: unknown): v is Record<string, unknown>[] =>\n  Array.isArray(v) && v.length > 0 && v.every((c) => !!c && typeof c === 'object' && !Array.isArray(c) && Object.keys(c).length > 0);","tryCatchPattern":null,"preventionTips":["Only wrap conditions in $and/$or when there are two or more.","Always use arrays (even single-element) for logical operator values.","Sanitize client-supplied filter JSON against the expected shape before forwarding."],"tags":["oracle","filters","logical-operators","validation"],"backgroundTag":null,"analyzedSha":"001c235229be8795e3834520467bd0d661ed8f34","analyzedAt":"2026-08-15T01:55:42.685Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}