Imagine it’s 4 PM on Friday. You have just launched a great feature that integrates your ERP and Salesforce via event-driven architecture. You celebrate with your teammates and leave the office. Suddenly your phone starts buzzing…
You see a message from Salesforce: Warning: Daily Platform Event limit exceeded.
You panic. It doesn’t make sense to hit the daily limit of platform events of tens of thousands within only 15 minutes. You run to your computer and check the developer console, but the logs are running so fast that you can’t even read them. You are stuck in an infinite loop.
Your mistake is that of many developers: you have fallen into the Platform Event Trap!
This is more than just a bad day scenario for a Salesforce developer. Event-driven architecture is a very powerful way to decouple complex business logic and scale to large data volumes. But if one is not careful with architectural design, it may turn into a resource-draining nightmare.
We are not going to just define the problem here. We are going to take a closer look at the Salesforce events, show how those infinite loops are formed in detail, and equip you with the Apex Triggers and best practices to make sure you won’t waste your Friday afternoons anymore.
Back to Basics: What Platform Events Are for
Before we get into what went wrong, let us first zero in on how things are supposed to work.
Platform events in Salesforce use a Publish/Subscribe (Pub/Sub) pattern. Imagine the scene of a radio station broadcast, the radio station is the broadcaster and the broadcaster is just sending out a signal. The broadcaster doesn’t know and doesn’t care who is listening. The broadcaster just sends the message out.
The listeners on the other hand are the subscribers. These could be Apex Triggers, flows or external systems like an ERP or a marketing platform. When they “hear” the message in the event, they react accordingly.
The main reason why developers like this pattern is that it allows processes to be decoupled. Instead of System A forcing System B to do something immediately (synchronous), System A just says, “Hey, this happened,” and System B deals with it when it can (asynchronously). This is very good for performance, especially when dealing with heavy integration or handling large data volumes.
However, this freedom comes with a risk. Because the publisher doesn’t control the subscriber, it creates a blind spot. If the subscriber reacts in a way that triggers the publisher again, you have a problem.
Dissecting the Platform Event Trap
What exactly is a Platform Event Trap?
To put it very simply, a Platform Event Trap is a situation where an event is published that triggers some processing, which inadvertently leads to the event getting published again (or a series of events resulting in the event being published again).
As Platform Events are asynchronous, the cycle behavior might not resemble the stack depth error one encounters running the synchronous Apex classes. Instead, it might be a train out of control.
The Hall of Mirrors metaphor
Imagine you entered a room where opposite walls have huge mirrors. When you light a candle, not only do you see one reflection but an infinite tunnel of candles going to infinity and beyond!
In the scenario of a Platform Event Trap, the initial event is your candle. Your “mirrors”, in this case, shall be your automation tools – triggers, flows, and process builders. When an event is fired, the mirror reflects it (processes it), and this reflection creates a new image (new event), which hits another mirror, and another, and another…
This “Mirror Room” effect uses up your organization’s resources—specifically your event limits (hourly and daily)—very quickly.
Why This Effect Occurs
The root cause is mostly the mismatch between the asynchronous nature of events and the synchronous nature of triggers that get executed as a result of events. When an event is published, the transaction is committed. The event bus picks it up and executes the trigger. From the perspective of the Salesforce platform, these are separate transactions. The platform does not automatically know that Transaction B is a consequence of Transaction A, and thus it is less straightforward for the platform’s built-in recursion defenses to intervene and stop the havoc.
Deep technical
In order to repair a Platform Event Trap, one must empathize with the bug i.e. put yourself in the position of the bug, here we consider the Apex Triggers.
Typically, the traps start after insert Apex triggers on the Platform Event Object. Here is a detailed break down of what happens in a typical failure:
- The Spark: An external system or user action publishes Order_Update__e (Event A).
- The Subscription: Your Apex Trigger, OrderUpdateTrigger, subscribes to this event. It fires when Event A arrives.
- The Logic: Inside the trigger, your code finds a related Opportunity record and updates its status to ‘Closed Won’.
- The Unintended Consequence: You have a separate trigger on the Opportunity object. When the Opportunity is updated, this trigger runs a check. It sees the status change and decides to sync this data back to the ERP. How does it do that? It publishes Order_Update__e.
- The Loop: We are now back at Step 1. The new event fires the original trigger again.
Symptoms to Monitor
How can you be sure you are trapped before hitting the hard limit? Here is a list of symptoms you should keep an eye on:
- Limit depletion going hyper-rapid: If in the span of just one hour your daily event delivery usage jumps from 1,000 to 50,000, you most certainly are trapped.
- LimitException errors: Besides error in your logs you might be seeing Apex CPU Time Limit exceeded as a result of the loop.
- CPU timeouts: While events are async, the processing of them consumes CPU time. If your org feels sluggish or other jobs are failing with Apex CPU time limit exceeded, a background loop might be hogging resources.
- Massive lag: If you publish an event and the change doesn’t happen for 20 minutes, your event bus is clogged with thousands of looping messages, creating a backlog.
Best Practices: Prevention, Mitigation
The best way to handle a Platform Event Trap is to never build one at all. Here are your architectural guards to prevent such a fall.
Recursion Control
Preventing recursive calls to trigger logic-originated is what is most frequently done using a static boolean flag in a handler class in the standard Apex triggers. You can do similarly here but since each event runs in a different transaction, be cautious.
However, within the execution of the event trigger itself you can prevent re-entry. Make sure your trigger handler creates a static set to keep track of which records it has already processed.
Idempotency
Thanks to the “Integration Ping-Pong” example, we saw that the trap is built when the two systems blindly update the record.
Much better is to check first whether the record value actually differs:
In this way when the ERP sends back “Active”, and the Salesforce record is already “Active”, the if statement returns false. No update happens. No event is published. The loop dies.
The “Guard Clause”
Write first certain criteria that the trigger must meet in order for it to run. If the event source is your own app, or the data is substantially unchanged, just return immediately. Don’t allow a CPU-intensive operation to be executed only to realize that it was unnecessary.
Publishing Conditionals
Under no circumstance should you publish an event outside an if statement. Very strict entry criteria should be applied in the following scenarios:
- Did the field really change? (look at the difference between Trigger.oldMap and Trigger.newMap).
- Is the user performing a record update an “Integration User”? If so, event publishing should probably be suppressed to prevent loops with external systems.
Conclusion
Platform Events are probably one of the most powerful instruments in the Salesforce ecosystem. They allow us to create modern, modular, and scalable enterprise applications. But like with all powerful things, a certain level of discipline is required.
The Platform Event Trap is a logical flaw, not a Salesforce bug. It is simply our forgetting that every action has a reaction. By adding idempotency, using strict guard clauses, and being aware of “Hall of Mirrors” recursion, the risk of event-driven architecture can be used at speed.
Before you launch your event-driven feature, take time to review your code. Walk the scenario. Question yourself: “If this event is triggered, what next? And what follows then?”
If you are able to trace the route back, that indicates you have a trap to fix. If the route comes to an end, then you are good to go .




