From 39551145b81fa671c8695dc0fc94f255c42e5ef6 Mon Sep 17 00:00:00 2001 From: Abhay Singh Date: Tue, 21 Jul 2026 12:48:15 +0530 Subject: [PATCH] fix(ts-oss): coerce non-string entity ids instead of crashing on trim() (#6263) Co-authored-by: kartik-mem0 --- mem0-ts/src/oss/src/memory/index.ts | 9 +++--- .../src/oss/tests/memory.validation.test.ts | 28 +++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/mem0-ts/src/oss/src/memory/index.ts b/mem0-ts/src/oss/src/memory/index.ts index 5ad72dd0c..d21951bb3 100644 --- a/mem0-ts/src/oss/src/memory/index.ts +++ b/mem0-ts/src/oss/src/memory/index.ts @@ -126,18 +126,19 @@ function rejectTopLevelEntityParams( /** * Validates and normalizes an entity ID. + * - Coerces non-string ids (e.g. numeric database keys) to string * - Trims leading/trailing whitespace * - Rejects empty or whitespace-only strings * - Rejects strings containing internal whitespace - * @returns The trimmed entity ID, or undefined if input is undefined + * @returns The trimmed entity ID, or undefined if input is undefined/null * @throws Error if entity ID is invalid */ function validateAndTrimEntityId( - value: string | undefined, + value: string | number | undefined | null, name: string, ): string | undefined { - if (value === undefined) return undefined; - const trimmed = value.trim(); + if (value == null) return undefined; + const trimmed = String(value).trim(); if (trimmed === "") { throw new Error( `Invalid ${name}: cannot be empty or whitespace-only. Provide a valid identifier.`, diff --git a/mem0-ts/src/oss/tests/memory.validation.test.ts b/mem0-ts/src/oss/tests/memory.validation.test.ts index 5503a8902..9efd96b6f 100644 --- a/mem0-ts/src/oss/tests/memory.validation.test.ts +++ b/mem0-ts/src/oss/tests/memory.validation.test.ts @@ -253,6 +253,34 @@ describe("Memory Input Validation", () => { }); }); + describe("non-string entity ID coercion", () => { + it("coerces an integer user_id in getAll filters to its string form", async () => { + const listSpy = jest + .spyOn((memory as any).vectorStore, "list") + .mockResolvedValue([[], 0]); + + await memory.getAll({ filters: { user_id: 42 as any } }); + + const passedFilters = listSpy.mock.calls[0][0] as Record; + expect(passedFilters.user_id).toBe("42"); + + listSpy.mockRestore(); + }); + + it("coerces an integer user_id in search filters to its string form", async () => { + const searchSpy = jest + .spyOn((memory as any).vectorStore, "search") + .mockResolvedValue([]); + + await memory.search("q", { filters: { user_id: 42 as any } }); + + const passedFilters = searchSpy.mock.calls[0][2] as Record; + expect(passedFilters.user_id).toBe("42"); + + searchSpy.mockRestore(); + }); + }); + describe("search() filter entity ID validation", () => { it("should throw error when user_id in filters is whitespace-only", async () => { await expect(