Loop Protection
Because automation actions can cascade — adding a tag fires a tag_applied trigger, which can add another tag,
and so on — Gordon CRM includes built-in safety mechanisms to prevent infinite loops.
The Problem
Consider this set of rules:
| Rule | Trigger | Action |
|---|---|---|
| Rule A | Tag "Lead" applied | Add tag "Prospect" |
| Rule B | Tag "Prospect" applied | Add tag "Lead" |
Without protection, this would create an infinite loop:
Tag "Lead" applied
→ Add "Prospect"
→ Tag "Prospect" applied
→ Add "Lead"
→ Tag "Lead" applied
→ Add "Prospect"
→ … (forever)Gordon CRM prevents this with two complementary strategies.
Strategy 1: Depth Limiter
The processAutomationTrigger function accepts an internal depth parameter (default 0). Every time an action
causes a cascading trigger, the depth is incremented:
processAutomationTrigger(…, depth = 0) ← Original trigger
→ add_tag action → fire tag_applied
processAutomationTrigger(…, depth = 1) ← First cascade
→ add_tag action → fire tag_applied
processAutomationTrigger(…, depth = 2) ← Second cascade
→ add_tag action → fire tag_applied
processAutomationTrigger(…, depth = 3) ← Third cascade
→ add_tag action → fire tag_applied
processAutomationTrigger(…, depth = 4) ← ABORTThe hard limit is depth > 3. When the depth exceeds 3, the engine stops additional cascading
to safeguard system stability.
This limit allows for legitimate chaining (up to 3 levels deep) while preventing runaway loops.
Depth-Limit Notifications
When the depth limit is hit, Gordon CRM creates a notification in the Notification Center so you have visibility into what happened. The notification includes enriched details identifying the specific trigger and the blocked rule:
Automation chain depth limit reached The automation engine stopped after 4 chain steps to prevent an infinite loop. Trigger: tag applied "Pong". Blocked automation: "When tag Pong added → Add tag Ping".
If multiple contacts hit the same chain, notifications are grouped into a single entry with a count (e.g., "×50") rather than creating separate alerts. See Notification Center → Automation Depth Limit for full details on grouping and interaction.
What To Do
A depth-limit notification usually means you have a circular tag automation chain — two or more rules that trigger each other in a loop. To resolve it:
- Click the "View Automations" link in the notification to go directly to the Automations page.
- Look for tag-based rules that form a cycle (e.g., "Tag A applied → Add Tag B" paired with "Tag B applied → Add Tag A").
- Remove or deactivate one side of the cycle.
- Check the Dependency Tracking cards on your Tags page to see the full picture of which tags trigger which automations.
Strategy 2: Idempotent Operations
Even without the depth limiter, the tag operations themselves provide a natural circuit breaker:
Add Tag (Idempotent)
The add_tag action uses an upsert with ON CONFLICT (contact_id, tag_id) DO NOTHING:
INSERT INTO contact_tags (contact_id, tag_id)
VALUES ($1, $2)
ON CONFLICT (contact_id, tag_id) DO NOTHING;If the contact already has the tag, the operation succeeds silently but no row is changed. The engine checks
the result — if no rows were affected (the tag was already present), it does not fire the cascading
tag_applied trigger. This naturally breaks the loop because the duplicate tag application produces no side effect.
Remove Tag (Idempotent)
The remove_tag action deletes the row and checks the SELECT return value. If no row was deleted (the tag
was already absent), the cascading tag_removed trigger is not fired.
How The Two Strategies Work Together
| Scenario | Strategy 1 (Depth) | Strategy 2 (Idempotency) |
|---|---|---|
| A → B → A (circular) | Would stop at depth 4 | Stops earlier — A is already applied, so the second application is a no-op |
| A → B → C → D → E (long chain) | Stops at depth 4 | Does not apply — each tag is different |
| A → A (self-referencing) | Would stop at depth 4 | Stops immediately — A is already applied |
In practice, idempotency catches most circular loops before the depth limiter kicks in. The depth limiter acts as a safety net for edge cases where a long chain of different tags might trigger each other in sequence.
Campaign Enrollment Protection
The enroll_campaign action has its own independent idempotency check:
- If the contact already has an
activeorprocessingenrollment → skip (no duplicate enrollment) - If a
triggerEventIdis present and acompletedenrollment exists for the same trigger event → skip (prevents webhook retries from re-enrolling)
These checks prevent a scenario where cascading tag automations could enroll the same contact into a campaign multiple times.
Best Practices
- Keep chains short. Design your automations to resolve within 1–2 cascade levels when possible.
- Avoid circular tag dependencies. If "Tag A applied → Add Tag B" exists, avoid creating "Tag B applied → Add Tag A".
- Use campaign enrollment wisely. Campaign enrollment is naturally idempotent, but long chains that lead to enrollment still consume processing time.
- Watch for depth-limit notifications. If the automation engine hits the depth limit, a notification appears in the Notification Center. This is the clearest signal that your automation chain is too long or contains a circular dependency — the notification body identifies the specific trigger and blocked rule.