Skip to content

Tool re-execution on task retry has no idempotency guard — duplicate payments, emails, trades possible #5802

@azender1

Description

@azender1

Description

When a CrewAI task fails and is retried — via max_retry_limit, exception handling, or external re-trigger — any @tool decorated function that already executed runs again. There's no mechanism to detect that a specific tool call already completed.

Steps to Reproduce

  1. Create a CrewAI agent with a @tool that calls an external API (payment, email, etc.)
  2. Have the tool execute successfully
  3. Simulate a failure after tool execution but before the agent receives confirmation
  4. Task retries
  5. The tool fires again — duplicate side effect

Expected behavior

A retry of the same logical tool call should return the original result without re-executing the side effect.

Screenshots/Code snippets

@tool
def send_payment(amount: float, recipient: str) -> str:
"""Send a payment to recipient"""
stripe.charge(amount, recipient) # fires twice on retry
return "payment sent"

Operating System

Windows 11

Python Version

3.10

crewAI Version

latest

crewAI Tools Version

lates

Virtual Environment

Venv

Evidence

See LangGraph Cloud issue #7417 for the same failure pattern documented in production: langchain-ai/langgraph#7417

Two independent parties confirmed the exact failure mode — in-memory dedup doesn't survive worker re-dispatch, and the fix requires durable external storage keyed before execution starts.

Possible Solution

Derive a stable request_id from tool arguments before execution, claim it in durable external storage, return the cached result on any retry with the same ID. The claim must happen outside the agent execution context so a retry on a new process hits the guard immediately.

Reference implementation: SafeAgent (pip install safeagent-exec-guard) — happy to contribute a CrewAI integration example.

Additional context

Same pattern documented in LangGraph Cloud issue #7417. The fix requires durable storage outside the framework, not in-memory or graph state.

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