Skip to content

Conversation

@murilosimao
Copy link

@murilosimao murilosimao commented Oct 24, 2025

Fixed #726

@murilosimao murilosimao changed the title fix: clean orphan tool_calls in AgentCoreMemorySaver to prevent Bedrock ValidationException fix(langgraph-checkpoint-aws): clean orphan tool_calls in AgentCoreMemorySaver to prevent Bedrock ValidationException Oct 24, 2025
@murilosimao
Copy link
Author

Hey @michaelnchin, could you please take a look at issue #726? I encountered the mentioned error when trying to use the new LangChain version.

Copy link
Collaborator

@michaelnchin michaelnchin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@murilosimao thanks for submitting both the issue and fix! LGTM in general, some feedback below.

Comment on lines +371 to +374
resolved_tool_call_ids = set()
for msg in messages:
if isinstance(msg, ToolMessage) and hasattr(msg, "tool_call_id"):
resolved_tool_call_ids.add(msg.tool_call_id)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: For very large message sets, it would be faster to create resolved_tool_calls directly from set comprehension:

Suggested change
resolved_tool_call_ids = set()
for msg in messages:
if isinstance(msg, ToolMessage) and hasattr(msg, "tool_call_id"):
resolved_tool_call_ids.add(msg.tool_call_id)
resolved_tool_call_ids = {
msg.tool_call_id
for msg in messages
if isinstance(msg, ToolMessage) and hasattr(msg, "tool_call_id")
}

Comment on lines +387 to +389
if len(valid_tool_calls) != len(msg.tool_calls):
cleaned_msg = msg.model_copy(update={"tool_calls": valid_tool_calls})
cleaned_messages.append(cleaned_msg)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that we're dropping possibly useful context from the message history, we should add a logger warning here to ensure that the tool call removals aren't completely silent.

# Clean up AIMessages with orphaned tool_calls
cleaned_messages = []
for msg in messages:
if isinstance(msg, AIMessage) and hasattr(msg, "tool_calls") and msg.tool_calls:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: AIMessage always has tool_calls attribute:

Suggested change
if isinstance(msg, AIMessage) and hasattr(msg, "tool_calls") and msg.tool_calls:
if isinstance(msg, AIMessage) and msg.tool_calls:

)


def clean_orphan_tool_calls(messages: list[Any]) -> list[Any]:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the tool calls is OK as an unblocker, but I'm slightly concerned about the conversational history loss prior to the checkpoint.

Maybe not in this PR, but we should consider to something less destructive. One possible solution would be to add dummy result ToolMessages:

...
    new_messages = []
    for msg in messages:
        new_messages.append(msg)

        if isinstance(msg, AIMessage) and msg.tool_calls:
            # Gather IDs of orphan tool_calls
            missing_tool_calls = [
                tc for tc in msg.tool_calls
                if tc.get("id") and tc["id"] not in resolved_ids
            ]

            # Create filler ToolMessages each orphan ID
            for tc in missing_tool_calls:
                new_messages.append(
                    ToolMessage(
                        tool_call_id=tc["id"],
                        content="Tool call failed or was cancelled.",
                    )
                )

    return new_messages

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: AgentCoreMemorySaver causes Bedrock ValidationException with orphaned tool_calls

2 participants