Test duplicate prevention before production: Define one protected effect and its expected count before each test.; Run retry cases: repeat after success, lost response, and concurrent delivery.; Verify downstream records match expected outcomes—no extra invoices or orders.
Image: Workflow Automation Guide

Error Handling

Part of Idempotency and duplicate prevention

Testing duplicate prevention before production

Test duplicate prevention with lost responses, concurrent delivery, changed inputs and legitimate new actions.

Test duplicate prevention by causing retries where the result is uncertain, then check the downstream business records. A green workflow status is insufficient if two invoices, orders or messages were produced. Before each test, define one protected effect and its expected count.

Set up an observable action

Use a non-production environment with a realistic downstream system, or a test endpoint that records requests and resulting objects. Give each test action a stable business ID, and record the initial state so a duplicate is distinguishable from an object left by an earlier test. Avoid using live customer data or sending real customer communications.

Specify what the system should do with a repeated request: return the original result, report an already-completed state, or halt for conflict. The exact response may vary, but the number of intended side effects should not increase after a repeat. Azure's messaging documentation and AWS Lambda guidance both describe the possibility of repeated processing, so retries should be a normal test path.

Exercise the failure windows

Run these cases separately:

  1. Repeat after success.Deliver the same event again and confirm no additional effect appears.
  2. Lost response.Let the downstream create call succeed, interrupt the workflow before it records success, then retry.
  3. Concurrent delivery.Start two workers on the same action and inspect the resulting objects.
  4. Changed input with the same key.Confirm the system detects a conflict instead of silently using the old result.
  5. Genuine new action.Send a second order or new billing period with similar details and confirm it is accepted.

The lost-response case is especially revealing: a local flag may still say “pending” while the external invoice already exists. The retry must find or safely recreate the result through the downstream system's idempotency contract. Stripe's documented key behaviour illustrates one possible contract, but other APIs need their own checks.

Inspect more than the log

For each case, compare the event ledger, workflow status and downstream record count. Check that both workers or retries point to the same result where appropriate. If one attempt was skipped, confirm the reason is visible to an operator. Verify that a key retained for the intended retry window will still be recognised after the workflow restarts.

Capture the observed output beside the expected output and rerun any failing case after a fix. Do not call an exercise “passed” merely because the automation did not throw an error. The final criterion is whether the business state matches the defined action: one effect for one intended action, and another effect when the user genuinely initiates a new one.

More from Error Handling