How to Fix 'duplicate tool calls when scaling' in CrewAI (Python)

By Cyprian AaronsUpdated 2026-04-21
duplicate-tool-calls-when-scalingcrewaipython

What this error actually means

If you’re seeing duplicate tool calls when scaling in CrewAI, it usually means the same tool invocation is being triggered more than once for a single agent step. In practice, this shows up when you scale from one agent or one task to multiple workers, or when your orchestration layer retries a run and replays the same tool call.

The common failure mode is not “CrewAI is broken.” It’s usually your agent setup, task wiring, or retry logic causing the same BaseTool call to be executed twice.

The Most Common Cause

The #1 cause is reusing mutable agent/task state across runs, especially when you create agents with shared tool instances and then execute them concurrently. CrewAI agents and tools should be treated as run-scoped objects unless you know they are safe to reuse.

Here’s the broken pattern:

BrokenFixed
Reuse one agent instance across concurrent executionsCreate fresh agents per run, or isolate state per thread/process
Share mutable tool instancesInstantiate tools inside the run or make them stateless
# BROKEN: shared agent/tool instance reused across scaling
from crewai import Agent, Task, Crew
from crewai_tools import SerperDevTool

search_tool = SerperDevTool()

researcher = Agent(
    role="Researcher",
    goal="Find relevant information",
    backstory="Web research specialist",
    tools=[search_tool],
    verbose=True,
)

def run_crew(topic: str):
    task = Task(
        description=f"Research {topic}",
        expected_output="A concise summary",
        agent=researcher,
    )

    crew = Crew(
        agents=[researcher],
        tasks=[task],
        verbose=True,
    )

    return crew.kickoff()
# FIXED: create isolated objects per execution
from crewai import Agent, Task, Crew
from crewai_tools import SerperDevTool

def build_crew(topic: str):
    search_tool = SerperDevTool()

    researcher = Agent(
        role="Researcher",
        goal="Find relevant information",
        backstory="Web research specialist",
        tools=[search_tool],
        verbose=True,
    )

    task = Task(
        description=f"Research {topic}",
        expected_output="A concise summary",
        agent=researcher,
    )

    return Crew(
        agents=[researcher],
        tasks=[task],
        verbose=True,
    )

def run_crew(topic: str):
    crew = build_crew(topic)
    return crew.kickoff()

If you’re scaling with threads, async workers, Celery, FastAPI background jobs, or multiple requests hitting the same process, this matters a lot. Shared agent state can cause repeated planning/execution cycles that look like duplicate tool calls.

Other Possible Causes

1. Retrying the same request without idempotency

If your API layer retries on timeout and the original request eventually succeeds, you’ll see the tool call twice.

# Example: retry wrapper without deduplication
for attempt in range(3):
    result = crew.kickoff()

Fix it by adding a request ID and deduping at the application layer.

request_id = "req_12345"
if not already_processed(request_id):
    result = crew.kickoff()
    mark_processed(request_id)

2. Multiple agents using the same tool instance concurrently

Some tools maintain internal session state. Reusing one instance across several agents can trigger repeated execution paths.

# BROKEN
shared_tool = SerperDevTool()

agent_a = Agent(..., tools=[shared_tool])
agent_b = Agent(..., tools=[shared_tool])

Prefer separate instances:

# FIXED
agent_a = Agent(..., tools=[SerperDevTool()])
agent_b = Agent(..., tools=[SerperDevTool()])

3. Task delegation causing repeated tool invocation

If you enable delegation and also give both manager and worker access to the same tool, both may call it.

manager = Agent(..., allow_delegation=True, tools=[SerperDevTool()])
worker = Agent(..., tools=[SerperDevTool()])

Reduce overlap. Only expose the tool to the agent that actually needs it.

4. Non-deterministic output parsing causing re-plans

If the model returns malformed output, CrewAI may re-ask for a valid action. That can repeat a tool call if your prompt encourages the same action again.

task = Task(
    description="Use search once and summarize.",
    expected_output="JSON only",
    agent=researcher,
)

Make outputs stricter and keep tool instructions explicit:

task = Task(
    description=(
        "Call SerperDevTool at most once. "
        "Then summarize results without calling any other tools."
    ),
    expected_output="JSON with keys: findings, sources",
    agent=researcher,
)

How to Debug It

  1. Turn on verbose logging

    • Set verbose=True on Agent and Crew.
    • Look for repeated lines like Using tool: SerperDevTool or repeated Action: entries in the same run.
  2. Check whether you are reusing objects

    • Search for module-level singletons:
      • search_tool = SerperDevTool()
      • agent = Agent(...)
      • crew = Crew(...)
    • If those live outside your request handler or job function, move them inside.
  3. Disable concurrency temporarily

    • Run one task at a time.
    • If the duplicate call disappears, your issue is likely shared state or race conditions in worker execution.
  4. Add request-level tracing

    • Log a unique request ID before every kickoff().
    • Log every tool invocation with that ID.
    • If one request ID maps to two identical tool calls, you’ve found your replay path.

Example:

import uuid

def handle_request(topic):
    request_id = str(uuid.uuid4())
    print(f"[{request_id}] starting kickoff")
    result = run_crew(topic)
    print(f"[{request_id}] done")

Prevention

  • Keep agents and tools scoped to a single run unless they are explicitly stateless.
  • Add idempotency keys around retries so failed HTTP requests do not replay completed crews.
  • Avoid giving the same external tool to multiple agents unless there’s a clear ownership model.

If you want a stable production setup in CrewAI, assume anything shared across requests will eventually get reused at the wrong time. Build for isolation first; optimize later.


Keep learning

By Cyprian Aarons, AI Consultant at Topiax.

Want the complete 8-step roadmap?

Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.

Get the Starter Kit

Related Guides