Skip to content

Agent-level retry creates duplicate charges — no idempotency guard above the tool layer #402

@azender1

Description

@azender1

Describe the bug

The SDK correctly generates idempotency keys for network-level retries within a session. The gap is at the agent level: when an agent framework retries a tool call as a new invocation (after a timeout, crash, or model loop), a new session starts with a new auto-generated key. The result is a second charge.
This is distinct from the SDK's retry handling — it's an orchestration-layer problem. The fix belongs above the tool, not inside it: generate a stable request_id from the tool call arguments before execution, claim it in durable storage, and return the cached receipt on any retry with the same ID.
I built a small Python guard that does exactly this: SafeAgent. Happy to show how it wraps the Stripe toolkit tools if useful, or contribute a reference implementation.

To Reproduce

  1. Build a LangChain or CrewAI agent using the Stripe toolkit
  2. Call create_payment_intent or create_charge as a tool
  3. Simulate a timeout before the agent receives confirmation
  4. Agent retries the tool call as a new invocation
  5. Two charges are created

Expected behavior

A retry of the same logical tool call with the same arguments should return the original receipt without executing a second charge.

Code snippets

OS

Linux

Language version

Python 3.10+

Library version

Latest

API version

Current

Additional context

This is an orchestration-layer problem, not an SDK bug. The fix belongs above the tool: generate a stable request_id from tool call arguments before execution, claim it in durable storage, return cached receipt on retry. Built a reference implementation: https://github.com/azender1/SafeAgent

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions