Skip to content

Bug: NullPointerException in MessageUtils.extractRecentToolCalls when assistant message has no name #1166

@Fruank4

Description

@Fruank4

Bug Description

MessageUtils.extractRecentToolCalls() calls .equals() directly on msg.getName() without a null check. Since Msg.name is an optional field that can be null, this throws a NullPointerException whenever an ASSISTANT message with no name is present in the message list.

Affected File

agentscope-core/src/main/java/io/agentscope/core/util/MessageUtils.java, line 54

Current Code

for (int i = messages.size() - 1; i >= 0; i--) {
    Msg msg = messages.get(i);
    if (msg.getRole() == MsgRole.ASSISTANT && msg.getName().equals(agentName)) {  // ← NPE here
        List<ToolUseBlock> toolCalls = msg.getContentBlocks(ToolUseBlock.class);
        if (!toolCalls.isEmpty()) {
            return toolCalls;
        }
        break;
    }
}

msg.getName() returns null when the message was constructed without a name (the field is not required by Msg.builder()). Calling .equals() on null throws NullPointerException.

Expected Behavior

The method should handle null names gracefully and simply skip messages where the name does not match.

Impact

  • Any ASSISTANT message in memory that was created without a name field will crash extractRecentToolCalls()
  • This method is called during the ReAct agent's acting phase to look up pending tool calls
  • The crash propagates up and terminates the agent's reasoning loop
  • Third-party integrations that construct Msg objects without names (a valid use of the API) are silently broken

Steps to Reproduce

// Create an assistant message without a name
Msg assistantMsg = Msg.builder()
    .role(MsgRole.ASSISTANT)
    // name intentionally omitted
    .content(TextBlock.builder().text("Hello").build())
    .build();

List<Msg> messages = List.of(assistantMsg);

// This throws NullPointerException
MessageUtils.extractRecentToolCalls(messages, "MyAgent");

Suggested Fix

Use Objects.equals() which handles null safely:

// Before
if (msg.getRole() == MsgRole.ASSISTANT && msg.getName().equals(agentName)) {

// After
if (msg.getRole() == MsgRole.ASSISTANT && Objects.equals(msg.getName(), agentName)) {

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    Status

    In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions