From 3ef54c1ec80efcf66b401af9712d38babb244b90 Mon Sep 17 00:00:00 2001 From: Sydney Runkle Date: Wed, 22 Apr 2026 08:27:34 -0400 Subject: [PATCH] fix(add_messages): guard fast path against None IDs and intra-right duplicates Two bugs in the fast-path optimisation: 1. The left-side type guard checked isinstance(BaseMessage) but not id is not None. Messages without IDs (e.g. HumanMessage(content="hi")) would skip ID assignment and return None IDs. 2. The pure-append short-circuit only checked for overlaps between right and left, not duplicates within right itself. A right list containing two messages with the same ID would bypass the slow-path deduplication and return both. Fixes: - Add left_seq[0].id is not None to the type-guard condition. - Replace the any() overlap check with a set-intersection check that also verifies len(right_id_set) == len(right_msgs) (no intra-right duplicates) before taking the fast return. Co-Authored-By: Claude Sonnet 4.6 --- libs/langgraph/langgraph/graph/message.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libs/langgraph/langgraph/graph/message.py b/libs/langgraph/langgraph/graph/message.py index 29be7be56..32ba4f78c 100644 --- a/libs/langgraph/langgraph/graph/message.py +++ b/libs/langgraph/langgraph/graph/message.py @@ -198,6 +198,7 @@ def add_messages( if ( left_seq and isinstance(left_seq[0], BaseMessage) + and left_seq[0].id is not None and not isinstance(left_seq[0], BaseMessageChunk) ): left_msgs = left_seq @@ -228,11 +229,12 @@ def add_messages( if remove_all_idx is not None: return right_msgs[remove_all_idx + 1 :] - # Optimization 2: pure-append fast path — no removals and no ID overlaps. - # Builds one set over left instead of copying left + building a full dict. + # Optimization 2: pure-append fast path — no removals, no ID overlaps with + # left, and no duplicate IDs within right (all imply a dedup/update is needed). if not has_remove: left_ids = {m.id for m in left_msgs} - if not any(m.id in left_ids for m in right_msgs): + right_id_set = {m.id for m in right_msgs} + if len(right_id_set) == len(right_msgs) and not (right_id_set & left_ids): result = left_msgs + right_msgs if format == "langchain-openai": return _format_messages(result)