Skip to main content
An infinite loop happens when a workflow writes data that re-triggers itself, duplicating writes and burning credits on every pass. The shape is almost always the same. A workflow listens for a change on an object, then makes a change to that same object, and that change satisfies its own trigger again. Nothing in the engine stops a workflow from feeding itself, so the loop runs until you notice the credit graph or disable the workflow. For a RevOps engineer, this is the difference between a quiet automation and a 2 a.m. incident. The good news is that loops are entirely preventable. Two cheap building blocks do most of the work, and both are free. The first is a scoped trigger, which watches only the attributes you choose. The second is an early Filter, which stops a run as soon as it sees the workflow’s own change. For anything that creates tasks, list entries, or sequence enrollments, add one more habit: before each write, ask what happens if it runs twice. This page shows the loop shapes that bite people, the guards that stop them, and the steps to take when one is already running. These guards cost no credits and no real build time. After reading, you can recognize a self-triggering design before you publish it, add the standard guard to any workflow that writes to the object it watches, and shut down a runaway in under a minute.

Recognizing the loop shape

The most common loop is a single workflow that both listens to and writes to the same object. A Record updated trigger fires. The workflow then runs an Update record block on that same record. The update satisfies the trigger, which fires the workflow again.
Run this once and the Runs tab fills with back-to-back executions on a single record. Each execution bills for the write inside it. The fix in the rest of this page is to make at least one link in that chain impossible. Either the write no longer satisfies the trigger, or an early filter rejects the workflow’s own writes.

Scoping the trigger

The first guard is to stop the trigger from watching the attribute the workflow writes. A Record updated trigger left unscoped fires on every change to any attribute. That means any write you make loops straight back into it. To break the chain at the source, scope the trigger to a single attribute, and never write that attribute from inside the workflow. Configure the trigger so its watched attribute and its written attributes never overlap. Because the workflow updates last_touched_at and the trigger only watches owner, the write can never re-fire the trigger, and the loop cannot start.

Adding an early filter

The second guard catches the case where you cannot fully separate the watched and written attributes. An early Filter checks who made the change. It lets human edits through and stops the run when the workflow itself authored the change. Filter on Updated by so a workflow-authored update no longer satisfies the trigger. Place the filter immediately after the trigger, before any write block. A run started by Priya Sharma editing the record passes the filter and continues. A run started by the workflow’s own write fails the filter and stops, so the loop ends after a single free, no-op pass. A stopped filter is not an error. It is the guard doing its job.

Guarding against duplicate writes

Loops are not the only re-run hazard. Retries, manual re-runs, and overlapping triggers can all execute a workflow twice on the same record. So for every write, ask one question: what happens if this runs twice? A second pass that creates another task, adds another list entry, or enrolls the contact again produces silent duplicates rather than an obvious loop. The cure is idempotency. An idempotent write is designed so a second run changes nothing. For records, the Create or update record block matches on a unique attribute and updates the existing record instead of creating a duplicate. Run this twice for jane@acme.com and the second pass updates the record found by the first, so you end with one person, not two. That match-or-create behavior is called an upsert. Tasks, list entries, and sequence enrollments have no built-in upsert. For those, add a Filter that first checks whether the task, entry, or enrollment already exists. Or stamp processed records with a workflow_processed_at timestamp and skip records that already carry one.

Limiting blast radius while testing

The cheapest insurance is to make a misbehaving workflow small before it can grow. A Record command trigger adds a manual Run workflow button instead of firing automatically. You can then run a risky workflow on one record at a time and watch the result before swapping in an automatic trigger. For workflows that fan out over many records, the Loop block’s Limit input caps how many iterations run. Set a low Limit on any loop while you are still testing. With the Limit set to 3, a loop that should touch 200 deals touches only 3 on each test run. A bad filter or a self-triggering write then costs three operations instead of two hundred. Raise the Limit only once a full trace in the run viewer looks correct. The new engine removed per-workflow credit caps, so the Loop Limit and a scoped trigger are your real spend controls, not a cap setting.

Responding to a runaway

When a loop is already running, stop the bleeding first and diagnose second. The order matters. Every second the workflow stays live, it bills for another pass.
1

Disable or archive the workflow

Disabling stops new runs; in-progress runs still complete. This halts the loop before you investigate anything.
2

Open the Runs tab and read the loop path

The Runs tab lists every execution and the credits each one consumed, so you can confirm the loop and measure the cost.
3

Identify the write that re-triggered the workflow

Trace from the trigger to the write block whose output satisfies the trigger again. That overlap is the loop.
4

Add a guard

Scope the trigger off the written attribute, or add an early Filter on Updated by → Type → is not → Workflow.
5

Test on one record before republishing

Re-run the workflow on a single record through a Record command trigger and confirm in the run viewer that it fires exactly once.
After the guard is in place and a single-record test fires once and stops, republish. Check the Runs tab again the next day to confirm the run volume on that object has returned to normal.
Loops bill for real. Every pass that includes a credited block charges again. That includes an Update record write, an enrollment, or an AI block. A loop left running overnight can consume a large share of your monthly allowance. Disable first, diagnose second. See credits and pricing for the full cost table.

See also


Source: Attio Workflows block library and Attio Workflows triggers. Last reviewed against the Attio Help Center, June 2026.