From 25bc1b74263a3c27725e95e7dc91945869f5cb2a Mon Sep 17 00:00:00 2001 From: Yash Singh <123385188+yashs33244@users.noreply.github.com> Date: Wed, 24 Jun 2026 11:10:36 +0530 Subject: [PATCH] fix(memory): guard against malformed image_url in parse_vision_messages (#5631) --- mem0-ts/src/oss/src/utils/memory.ts | 8 +++++--- mem0/memory/utils.py | 5 ++++- tests/memory/test_memory_utils.py | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/mem0-ts/src/oss/src/utils/memory.ts b/mem0-ts/src/oss/src/utils/memory.ts index 832809369..26c18c730 100644 --- a/mem0-ts/src/oss/src/utils/memory.ts +++ b/mem0-ts/src/oss/src/utils/memory.ts @@ -31,9 +31,11 @@ const parse_vision_messages = async (messages: Message[]) => { typeof message.content === "object" && message.content.type === "image_url" ) { - const description = await get_image_description( - message.content.image_url.url, - ); + const imageUrl = message.content.image_url?.url; + if (!imageUrl) { + throw new Error("image_url content part is missing image_url.url"); + } + const description = await get_image_description(imageUrl); new_message.content = typeof description === "string" ? description diff --git a/mem0/memory/utils.py b/mem0/memory/utils.py index dbfd3384d..dd7b1e4cc 100644 --- a/mem0/memory/utils.py +++ b/mem0/memory/utils.py @@ -206,7 +206,10 @@ def parse_vision_messages(messages, llm=None, vision_details="auto"): elif isinstance(content, dict) and content.get("type") == "image_url": if llm is None: continue - image_url = content["image_url"]["url"] + image_url_obj = content.get("image_url") + image_url = image_url_obj.get("url") if isinstance(image_url_obj, dict) else None + if not image_url: + raise ValueError("image_url content part is missing image_url.url") try: description = get_image_description(image_url, llm, vision_details) returned_messages.append({"role": role, "content": description}) diff --git a/tests/memory/test_memory_utils.py b/tests/memory/test_memory_utils.py index 820729133..49c55c5cb 100644 --- a/tests/memory/test_memory_utils.py +++ b/tests/memory/test_memory_utils.py @@ -96,6 +96,24 @@ class TestParseVisionMessages: result = parse_vision_messages(messages, llm=None) assert result == messages + def test_malformed_image_dict_raises_value_error(self): + # A malformed image part (missing the nested url) used to raise an + # uncaught KeyError that aborted add(); it should raise a clear ValueError. + mock_llm = Mock() + messages = [{"role": "user", "content": {"type": "image_url", "image_url": {}}}] + with pytest.raises(ValueError, match=r"missing image_url\.url"): + parse_vision_messages(messages, llm=mock_llm) + mock_llm.generate_response.assert_not_called() + + def test_none_image_url_raises_value_error(self): + # image_url present but None (or any non-dict) must also raise the clear + # ValueError, not an AttributeError from calling .get() on None. + mock_llm = Mock() + messages = [{"role": "user", "content": {"type": "image_url", "image_url": None}}] + with pytest.raises(ValueError, match=r"missing image_url\.url"): + parse_vision_messages(messages, llm=mock_llm) + mock_llm.generate_response.assert_not_called() + class TestRemoveSpacesFromEntities: """