{"record":{"id":"1e4871e69a7ead86","repo":"mem0ai/mem0","slug":"top-level-entity-parameters-invalidkeys-join-1e4871","errorCode":null,"errorMessage":"Top-level entity parameters [${invalidKeys.join(\", \")}] are not supported in ${methodName}(). Use filters: { userId: \"...\" } instead.","messagePattern":"Top-level entity parameters \\[(.+?)\\] are not supported in (.+?)\\(\\)\\. Use filters: (.+?) instead\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mem0-ts/src/oss/src/memory/index.ts","lineNumber":145,"sourceCode":"}\n\n// Batch size for deleteAll pagination. Larger than most vector store default\n// page limits (~100) to minimize roundtrips while bounded to avoid memory pressure.\nconst DELETE_ALL_BATCH_SIZE = 1000;\n\n/**\n * Validates that no top-level entity parameters are passed in config.\n * @throws Error if entity params are found at top level\n */\nfunction rejectTopLevelEntityParams(\n  config: Record<string, any>,\n  methodName: string,\n): void {\n  const invalidKeys = Object.keys(config).filter((k) =>\n    ENTITY_PARAMS.includes(k),\n  );\n  if (invalidKeys.length > 0) {\n    throw new Error(\n      `Top-level entity parameters [${invalidKeys.join(\", \")}] are not supported in ${methodName}(). ` +\n        `Use filters: { userId: \"...\" } instead.`,\n    );\n  }\n}\n\n/**\n * Validates and normalizes an entity ID.\n * - Coerces non-string ids (e.g. numeric database keys) to string\n * - Trims leading/trailing whitespace\n * - Rejects empty or whitespace-only strings\n * - Rejects strings containing internal whitespace\n * @returns The trimmed entity ID, or undefined if input is undefined/null\n * @throws Error if entity ID is invalid\n */\nfunction validateAndTrimEntityId(\n  value: string | number | undefined | null,\n  name: string,","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/mem0ai/mem0/blob/001c235229be8795e3834520467bd0d661ed8f34/mem0-ts/src/oss/src/memory/index.ts#L127-L163","documentation":"Thrown by Memory's parameter validation when a caller passes entity identifiers (user_id/agent_id/run_id in snake_case or camelCase) as top-level keys of the options object instead of nested under filters. The OSS TS SDK requires scoping entities via filters: { userId: '...' } so it rejects the flatter Python-style or older-TS-style shape with an error naming the offending keys and the method.","triggerScenarios":"Calling memory.add(msgs, { user_id: 'u1' }) or memory.search(q, { agentId: 'a1' }) — any *_id key at the top level of the config argument. Also triggered by code ported from the Python SDK or from older mem0-ts versions that accepted top-level entity params.","commonSituations":"Migrating Python mem0 code to mem0-ts and copying kwargs verbatim; upgrading from an older mem0ai npm version that tolerated top-level ids; AI-generated examples using the Python shape; passing a merged object that accidentally includes user_id from upstream data.","solutions":["Move entity ids into filters: memory.add(messages, { filters: { userId: 'u1' } }).","Audit call sites for user_id/agent_id/run_id (both casings) in the options object — the error message lists exactly which keys offended.","If porting from Python, mechanically translate every top-level id kwarg into the filters object.","Update to current docs/examples for the TS SDK shape."],"exampleFix":"// before\nawait memory.add('user prefers dark mode', { user_id: 'u1', agent_id: 'a1' }); // throws\n\n// after\nawait memory.add('user prefers dark mode', {\n  filters: { userId: 'u1', agentId: 'a1' },\n});","handlingStrategy":"validation","validationCode":"const ENTITY_KEYS = ['user_id', 'agent_id', 'run_id', 'userId', 'agentId', 'runId'];\nfunction assertNoTopLevelEntityParams(options: Record<string, unknown>, method: string) {\n  const bad = Object.keys(options ?? {}).filter((k) => ENTITY_KEYS.includes(k));\n  if (bad.length > 0) {\n    throw new TypeError(`${method}(): pass ${bad.join(', ')} inside filters, not at top level`);\n  }\n}","typeGuard":"function isFiltersShaped(options: Record<string, any> | undefined): boolean {\n  if (!options) return true;\n  return !Object.keys(options).some((k) =>\n    ['user_id', 'agent_id', 'run_id', 'userId', 'agentId', 'runId'].includes(k),\n  );\n}","tryCatchPattern":"try {\n  await memory.add(messages, options as any);\n} catch (err) {\n  if (err instanceof Error && /Top-level entity parameters/.test(err.message)) {\n    const { user_id, agent_id, run_id, ...rest } = options as any;\n    await memory.add(messages, { ...rest, filters: { userId: user_id, agentId: agent_id, runId: run_id } });\n    return;\n  }\n  throw err;\n}","preventionTips":["Type your call sites with AddMemoryOptions/SearchOptions so top-level ids fail at compile time.","Never port Python kwargs verbatim — translate entity ids into filters in the TS port.","Add a lint/unit rule rejecting user_id/agent_id/run_id keys in Memory option objects."],"tags":["validation","api-shape","filters","migration","typescript"],"backgroundTag":null,"analyzedSha":"001c235229be8795e3834520467bd0d661ed8f34","analyzedAt":"2026-08-15T01:55:42.685Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}