How to Fix 'duplicate tool calls during development' in CrewAI (Python)

By Cyprian AaronsUpdated 2026-04-21
duplicate-tool-calls-during-developmentcrewaipython

What this error means

If you’re seeing duplicate tool calls during development in CrewAI, it usually means the same tool invocation is being triggered more than once in a single run. In practice, this shows up when an agent retries, when your task logic runs twice, or when you accidentally register the same tool in multiple places.

The annoying part is that the stack trace often points at CrewAI internals, not your actual bug. The fix is usually in your agent/task wiring, not in the tool itself.

The Most Common Cause

The #1 cause is duplicating the same tool call path by reusing mutable state or invoking crew.kickoff() more than once during app startup or debugging.

A very common pattern is creating agents/tasks at module import time and then calling kickoff from code that gets executed twice, such as a hot-reload loop, notebook cell rerun, or FastAPI startup hook.

Broken vs fixed pattern

Broken patternFixed pattern
Calls kickoff() at import time or inside code that runs twiceWraps execution in a single entrypoint
Reuses the same mutable tools list across runsBuilds fresh agent/crew objects per run
Hard to tell where duplicate calls come fromClear lifecycle boundary
# broken.py
from crewai import Agent, Task, Crew
from crewai_tools import SerperDevTool

search_tool = SerperDevTool()

tools = [search_tool]

agent = Agent(
    role="Researcher",
    goal="Find company info",
    backstory="You research companies",
    tools=tools,
)

task = Task(
    description="Search for ACME Corp",
    expected_output="Company summary",
    agent=agent,
)

crew = Crew(agents=[agent], tasks=[task])

# BAD: this can run multiple times in dev environments
result = crew.kickoff()
print(result)
# fixed.py
from crewai import Agent, Task, Crew
from crewai_tools import SerperDevTool

def build_crew():
    search_tool = SerperDevTool()

    agent = Agent(
        role="Researcher",
        goal="Find company info",
        backstory="You research companies",
        tools=[search_tool],
    )

    task = Task(
        description="Search for ACME Corp",
        expected_output="Company summary",
        agent=agent,
    )

    return Crew(agents=[agent], tasks=[task])

if __name__ == "__main__":
    crew = build_crew()
    result = crew.kickoff()
    print(result)

If you’re using Streamlit, FastAPI reload mode, Jupyter, or any dev server with auto-reload, this is the first thing to fix.

Other Possible Causes

1. The same tool is attached at both agent and task level

CrewAI can end up resolving the same tool more than once if you pass it through multiple layers.

# broken
agent = Agent(..., tools=[search_tool])
task = Task(..., agent=agent, tools=[search_tool])  # duplicate registration

Fix it by attaching tools in one place only.

# fixed
agent = Agent(..., tools=[search_tool])
task = Task(..., agent=agent)

2. Your custom tool method is not idempotent

If the LLM retries the call or your code invokes the same action twice, a non-idempotent tool can make the issue look like a CrewAI bug.

class WriteToCRMTool:
    def _run(self, customer_id: str):
        # bad: creates a new record every time
        crm.create_note(customer_id=customer_id, note="Follow up")

Make it safe to repeat.

class WriteToCRMTool:
    def _run(self, customer_id: str):
        existing = crm.find_note(customer_id=customer_id, note="Follow up")
        if existing:
            return "Note already exists"
        crm.create_note(customer_id=customer_id, note="Follow up")
        return "Note created"

3. Your agent has overlapping instructions that trigger repeated tool use

If your prompt says “keep searching until you’re certain” and also asks for multiple sources, the model may call the same search tool repeatedly.

agent = Agent(
    role="Analyst",
    goal="Research thoroughly and verify everything multiple times",
    backstory="...",
    tools=[search_tool],
)

Tighten the instruction:

agent = Agent(
    role="Analyst",
    goal="Find 3 relevant sources and stop",
    backstory="...",
    tools=[search_tool],
)

4. You are reusing a global Crew instance across requests

This happens a lot in web apps and notebooks.

# broken: global singleton reused across requests
crew = build_crew()

@app.post("/run")
def run():
    return crew.kickoff()

Build per request instead:

@app.post("/run")
def run():
    crew = build_crew()
    return crew.kickoff()

How to Debug It

  1. Check whether your entrypoint runs twice

    • Add a log before kickoff().
    • If you see it twice on one request/run, you have an app lifecycle problem.
    • Common offenders: uvicorn --reload, Streamlit reruns, notebook cells.
  2. Print the final tools attached to each agent

    • Confirm each tool appears once.
    • Look for accidental duplication from config merges or helper functions.
print([type(t).__name__ for t in agent.tools])
  1. Disable retries temporarily

    • If your setup uses retry logic around Crew.kickoff(), turn it off.
    • A retry wrapper can make one failure look like repeated duplicate calls.
  2. Reduce to one task and one tool

    • Start with a single Agent, single Task, single SerperDevTool.
    • If the error disappears, add pieces back until it returns.
    • That tells you whether the issue is lifecycle, prompt-driven repetition, or duplicated wiring.

Prevention

  • Build crews inside functions, not at module import time.
  • Attach each tool in exactly one place: either on the Agent or via your own orchestration layer.
  • Make custom tools idempotent so repeated calls don’t create duplicate side effects.
  • In dev mode, watch for auto-reload behavior that reruns startup code and triggers extra Crew.kickoff() executions.

If you want one rule to remember: treat CrewAI objects as runtime instances, not global singletons. That alone eliminates most duplicate tool call issues during development.


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