Skip to content

[BUG] batch tool is completely broken - two issues prevent any sub-tool execution #413

@pkunekar

Description

@pkunekar

Checks

  • I have updated to the lastest minor and patch version of Strands
  • I have checked the documentation and this is not expected behavior
  • I have searched ./issues and there are no duplicates of my issue

Strands Version

1.29.0

Tools Package Version

0.2.22

Tools used

  1. batch
  2. current_time

Python Version

3.12.12

Operating System

Windows, Linux(ARM64)

Installation Method

pip

Steps to Reproduce

from strands import Agent
from strands_tools import batch, current_time

agent = Agent(tools=[batch, current_time])
result = agent("What is the current time in UTC, US/Pacific, US/Eastern, Europe/London, Asia/Tokyo, and Australia/Sydney?")

The LLM generates this tool call:

batch (invocations: [
    {'name': 'current_time', 'arguments': {'timezone': 'UTC'}},
    {'name': 'current_time', 'arguments': {'timezone': 'US/Pacific'}},
    {'name': 'current_time', 'arguments': {'timezone': 'US/Eastern'}},
    {'name': 'current_time', 'arguments': {'timezone': 'Europe/London'}},
    {'name': 'current_time', 'arguments': {'timezone': 'Asia/Tokyo'}},
    {'name': 'current_time', 'arguments': {'timezone': 'Australia/Sydney'}}
])

Expected Behavior

The batch tool should execute all 6 current_time invocations and return their results:

Batch execution completed with 6 tool(s):
✓ current_time: Success
✓ current_time: Success
...

Actual Behavior

With unpatched code (Bug 1):

The batch tool returns 0 results — invocations is silently empty:

Batch execution completed with 0 tool(s):
{"batch_summary": {"failed": 0, "successful": 0, "total_tools": 0}, "results": []}

After fixing Bug 1 only [locally] (Bug 2 surfaces):

All 6 sub-tool calls fail with ConcurrencyException:

2026-03-10 17:26:33,510 - strands.agent - INFO - Tool #1: batch
Error executing tool 'current_time': Direct tool call cannot be made while the agent is
in the middle of an invocation. Set record_direct_tool_call=False to allow direct tool
calls during agent invocation.
Error executing tool 'current_time': Direct tool call cannot be made while the agent is
in the middle of an invocation. Set record_direct_tool_call=False to allow direct tool
calls during agent invocation.
... (repeated for all 6 invocations)

Additional Context

No response

Possible Solution

Bug 1: invocations read from wrong source (line 97)

Root Cause

The bug is in src/strands_tools/batch.py line 97:

def batch(tool: ToolUse, **kwargs) -> ToolResult:
    agent = kwargs.get("agent")
    invocations = kwargs.get("invocations", [])  # ← BUG: always returns []

The batch tool is a module-based tool (uses TOOL_SPEC + function, not @tool decorator), so it is loaded as a PythonAgentTool. When PythonAgentTool.stream() calls the tool function, it passes:

# strands/tools/tools.py line 259
result = await asyncio.to_thread(self._tool_func, tool_use, **invocation_state)
  • tool_use (first arg → tool param): Contains {"toolUseId": "...", "name": "batch", "input": {"invocations": [...]}}
  • **invocation_state (→ **kwargs): Contains {"agent": <Agent>, "model": ..., "messages": ..., "system_prompt": ..., "tool_config": ...}

So kwargs has agent, model, messages, etc. — but NOT invocations. The invocations array is in tool["input"]["invocations"].

Compare this with DecoratedFunctionTool.stream() (used by @tool decorated functions like current_time) which correctly extracts tool_use.get("input", {}) and passes validated input to the function.

Current behavior (line 97)

invocations = kwargs.get("invocations", [])

Proposed Fix (line 97)

invocations = tool.get("input", {}).get("invocations", [])

Bug 2: Sub-tool calls fail with ConcurrencyException (line 112)

Root Cause

After fixing Bug 1, the batch tool correctly iterates over invocations and calls sub-tools via agent.tool.<name>(**arguments) on line 112:

result = tool_fn(**arguments)  # ← BUG: missing record_direct_tool_call=False

Since batch is called during an active agent invocation, the agent holds its invocation lock. When agent.tool.current_time(...) is called, the SDK's ToolCaller (strands/tools/_caller.py lines 88-96) tries to acquire the same lock and raises:

ConcurrencyException: Direct tool call cannot be made while the agent is in the middle
of an invocation. Set record_direct_tool_call=False to allow direct tool calls during
agent invocation.

The ToolCaller accepts record_direct_tool_call=False to skip the lock (and skip recording in message history), which is exactly what batch sub-tool calls need.

Current behavior (line 112)

result = tool_fn(**arguments)

Proposed Fix (line 112)

result = tool_fn(record_direct_tool_call=False, **arguments)

Summary of all changes needed in src/strands_tools/batch.py

- invocations = kwargs.get("invocations", [])
+ invocations = tool.get("input", {}).get("invocations", [])
-                     result = tool_fn(**arguments)
+                     result = tool_fn(record_direct_tool_call=False, **arguments)

Related Issues

  • Bug 1 may also affect other module-based tools (TOOL_SPEC + function pattern) that read their input arguments from kwargs instead of tool["input"].
  • Bug 2 would affect any tool that makes direct agent.tool.<name>() calls during an active agent invocation.

PFB Screenshot after fixing both bugs:

Image

Related Issues

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions