From 1bd99103821398aa0d77fd9dbe12d7243b2e51b4 Mon Sep 17 00:00:00 2001 From: Himanshu-Sangshetti Date: Thu, 23 Jul 2026 11:49:25 +0530 Subject: [PATCH] fix(zapier): harden null-body handling and error messages From an independent review pass: - Guard search / get / add against a null or empty 2xx body (previously an uncaught TypeError on .results / .status); return [] or an empty object. - Stringify non-string API error detail so a thrown message never renders as "[object Object]". - Correct the Add sample to the default no-wait shape {event_id, status}. - Add a regression unit test for the null-body path. Verified: build + zapier validate + 16 tests (13 unit, 3 live E2E), plus a live check of the v3-add to /v1/event poll cross-version path. --- integrations/zapier-mem0/src/creates/add_memory.ts | 7 +++++-- integrations/zapier-mem0/src/middleware.ts | 10 +++++----- .../zapier-mem0/src/searches/get_memories.ts | 5 +++-- .../zapier-mem0/src/searches/search_memories.ts | 6 +++--- integrations/zapier-mem0/test/unit.test.ts | 12 ++++++++++++ 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/integrations/zapier-mem0/src/creates/add_memory.ts b/integrations/zapier-mem0/src/creates/add_memory.ts index 853aaba96..9a2dcc69a 100644 --- a/integrations/zapier-mem0/src/creates/add_memory.ts +++ b/integrations/zapier-mem0/src/creates/add_memory.ts @@ -77,7 +77,9 @@ const perform = async (z: ZObject, bundle: Bundle): Promise= 400) { const data = (response.data as Record) || {}; - const detail = (data.detail || - data.error || - data.message || - response.content || - 'unknown error') as string; + const raw = + data.detail || data.error || data.message || response.content || 'unknown error'; + // DRF sometimes returns detail as an object/array; stringify so the + // thrown message never renders as "[object Object]". + const detail = typeof raw === 'string' ? raw : JSON.stringify(raw); throw new z.errors.Error( `Mem0 API request failed (HTTP ${response.status}): ${detail}`, 'Mem0ApiError', diff --git a/integrations/zapier-mem0/src/searches/get_memories.ts b/integrations/zapier-mem0/src/searches/get_memories.ts index 155373179..96df8d3ee 100644 --- a/integrations/zapier-mem0/src/searches/get_memories.ts +++ b/integrations/zapier-mem0/src/searches/get_memories.ts @@ -16,8 +16,9 @@ const perform = async (z: ZObject, bundle: Bundle): Promise => { }, body, }); - const data = response.data as Memory[] | { results?: Memory[] }; - return Array.isArray(data) ? data : data.results || []; + // Guard against a null/empty body; always return an array. + const data = response.data as Memory[] | { results?: Memory[] } | null; + return Array.isArray(data) ? data : data?.results ?? []; }; export default { diff --git a/integrations/zapier-mem0/src/searches/search_memories.ts b/integrations/zapier-mem0/src/searches/search_memories.ts index d2869bbc5..f2f834e45 100644 --- a/integrations/zapier-mem0/src/searches/search_memories.ts +++ b/integrations/zapier-mem0/src/searches/search_memories.ts @@ -16,9 +16,9 @@ const perform = async (z: ZObject, bundle: Bundle): Promise => { method: 'POST', body, }); - // Searches must return an array. - const data = response.data as Memory[] | { results?: Memory[] }; - return Array.isArray(data) ? data : data.results || []; + // Searches must return an array; guard against a null/empty body. + const data = response.data as Memory[] | { results?: Memory[] } | null; + return Array.isArray(data) ? data : data?.results ?? []; }; export default { diff --git a/integrations/zapier-mem0/test/unit.test.ts b/integrations/zapier-mem0/test/unit.test.ts index 168c2ed91..66f472019 100644 --- a/integrations/zapier-mem0/test/unit.test.ts +++ b/integrations/zapier-mem0/test/unit.test.ts @@ -124,6 +124,18 @@ describe('search / get array-shape enforcement (offline)', () => { } as any); expect(z.requests[0].params).toEqual({ page: 2, page_size: 10 }); }); + + it('search and get_memories return [] on a null/empty body (no crash)', async () => { + const zSearch = makeZ([{ data: null }]); + const found = await searchMemories.operation.perform(zSearch, { + inputData: { query: 'x', user_id: 'u1' }, + } as any); + expect(found).toEqual([]); + + const zGet = makeZ([{ data: null }]); + const all = await getMemories.operation.perform(zGet, { inputData: { user_id: 'u1' } } as any); + expect(all).toEqual([]); + }); }); describe('delete_memory (offline)', () => {