unguarded-side-effect
errorA non-idempotent effect (payment, email, plain insert, increment) runs with no dedupe guard on its path.
Why it goes wrong
Webhook providers and queues deliver at least once. A timeout, deploy, or manual resend runs the handler again with the same event, and every unguarded effect happens again.
Safe pattern
Claim the event atomically before the effect (unique insert in the same transaction as DB writes, or Redis SET NX), or pass the provider's idempotency key derived from the event id.
See it in the playground →
An example handler that triggers this rule.
Safe patterns guide →
Keys, transactions, leases, and status codes.
Configure
// retrysafe.config.ts
export default defineConfig({
rules: { "unguarded-side-effect": "error" }, // or "off"
});
// or, for one line (a reason is required):
// retrysafe-ignore unguarded-side-effect -- <why this is safe>