Direct answer: When a Home Assistant automation runs twice, do not add a delay or change its run mode first. Open two traces and compare the trigger description, trigger ID, timestamp and action path. Most duplicate-looking runs come from two valid triggers, a state trigger that matches more transitions than intended, the same automation loaded twice, an event emitted twice by the source integration, or two different automations calling the same action. The trace evidence tells you which branch to fix.
Quick diagnostic box
- Time: about 15 minutes if traces exist.
- Risk: low when you inspect first and change one automation at a time.
- Start here: open Settings → Automations & scenes, select the automation, open Traces, and compare the two runs.
- Preserve evidence: record both timestamps, trigger descriptions, trigger IDs, run IDs and the action that appeared twice.
- Do not delete the automation, add a random delay, or switch to mode: single before you identify whether there were actually two triggers.
First decide what “twice” means
Two notifications, two light commands or two logbook entries do not necessarily prove that one automation ran twice. A single run can call the same action from two branches, a script can repeat an action, a device can report the same change twice, and two separate automations can target the same service. Conversely, one automation can legitimately start two runs milliseconds apart.
Use traces as the source of truth. If there are two trace entries with different run IDs, Home Assistant started the automation twice. If there is one trace with two action calls, the duplication is inside the action sequence, script or downstream integration. If there is only one action call but the device responds twice, investigate the target integration or device rather than the automation trigger.
Preserve the evidence before reloading
Home Assistant stores a limited number of traces by default. A reload or edit can make the original state harder to reconstruct. Open both traces and note the exact time, trigger, changed entity, from/to values and path through conditions and choose blocks. Export or copy only the minimum sanitized details required. Remove tokens, webhook IDs, personal locations, device serials, public URLs and notification contents.
For YAML automations, Home Assistant documentation allows the number of stored traces to be increased with the trace stored_traces option. Do this only when the problem is intermittent and existing traces are being overwritten; it does not repair duplicate execution.
Ranked cause 1: two triggers are both valid
Multiple triggers in one automation are evaluated independently. If a motion sensor changes state and a related helper or template changes moments later, both may start the automation. Time, sun, state and event triggers can also overlap at a boundary. Give each trigger a unique ID and compare trigger.id in the trace. The IDs turn an ambiguous duplicate into a measurable pattern.
triggers:
- trigger: state
entity_id: binary_sensor.kitchen_motion
to: "on"
id: motion_started
- trigger: state
entity_id: input_boolean.kitchen_override
to: "on"
id: override_started
If either trigger is sufficient, two runs may be correct. Prevent the duplicate at the logic level: choose one source of truth, add a condition that excludes the overlapping case, or branch by trigger ID so both triggers do not execute the same action. Do not use a blanket delay as a substitute for understanding the overlap.
Ranked cause 2: a state trigger matches more transitions than intended
A state trigger without a to or from filter can fire when the entity changes state and, depending on the entity and configuration, attribute changes may also matter. A template trigger can become true again after briefly returning false. Numeric thresholds trigger when crossing the boundary, not continuously, but noisy measurements can cross back and forth.
In each trace, inspect from_state and to_state. If the meaningful state is identical but an attribute changed, narrow the trigger. If the state bounced off and on, fix the noisy source if possible or use a documented duration only when the desired behavior truly requires the state to remain stable. Remember that Home Assistant’s for option does not survive an automation reload or Home Assistant restart.
Ranked cause 3: the same automation is loaded twice
This occurs when equivalent logic exists in the UI and YAML, when an automation was copied and renamed, or when an include causes the same file to be referenced unexpectedly. Search the automation list for the target entity, notification text or distinctive alias. In YAML, confirm that each automation has a unique ID and that automations.yaml remains a list.
Do not remove files blindly. Disable one suspected duplicate, trigger the original condition once, then review traces. If the second run disappears, document which definition remains authoritative before deleting or consolidating anything.
Ranked cause 4: two automations call the same script or service
A duplicated outcome may come from different parents. Search for the service call, script entity, scene, notification message or target entity across automations and scripts. A script trace can show two callers even when each parent automation ran only once. The clean repair is usually to consolidate the shared decision into one automation or make the script idempotent where practical.
Idempotent means a repeated request leaves the system in the same safe state. Turning a light on is often naturally idempotent; sending a notification, incrementing a counter, unlocking a door or making an API request may not be. High-impact actions deserve explicit guards and verification.
Ranked cause 5: the source integration emits two events
Some devices expose both a state change and an event. A button integration may create a device trigger plus an event trigger for the same press. MQTT can deliver retained or repeated messages depending on publisher behavior and quality-of-service configuration. Mobile apps, webhooks and cloud integrations can retry requests.
Compare event data and timestamps in the traces. If the automation received two genuinely separate source events, the trigger is behaving as configured. Correct the publisher when possible. If correction is impossible, use a narrow guard based on a stable event identifier or a short helper-based deduplication window that matches the source behavior. Document the tradeoff: any deduplication rule can suppress legitimate rapid actions.
Ranked cause 6: actions repeat inside one run
Open the trace timeline and count action nodes. Check repeat blocks, parallel sequences, choose branches, scripts and wait/restart paths. A common mistake is to place the same service call before and after a choose block, or to call a script directly and again through a scene or another script.
Fix the duplicated branch rather than changing trigger behavior. Retest the automation manually only after confirming that manual execution is safe; the Run actions control skips normal trigger timing and can make destructive or noisy actions happen immediately.
Why automation mode is not the first fix
Home Assistant modes control what happens when a new run starts while another is active. Single rejects a new overlapping run; restart stops the old run and starts the new one; queued waits; parallel allows independent runs. A mode can change the visible symptom, but it does not explain why two triggers occurred.
If an automation finishes in 100 milliseconds and the second trigger arrives later, mode single will not block it. If you switch to restart, the first run may be interrupted halfway. If you use queued, both unwanted runs may still execute. Select mode based on the intended concurrency after fixing trigger logic.
A privacy-safe trace comparison
Run A
time: 2026-09-29 18:42:10.218
trigger_id: motion_started
entity: binary_sensor.room_motion
from: "off"
to: "on"
action_path: choose/0/sequence/0
Run B
time: 2026-09-29 18:42:10.463
trigger_id: occupancy_started
entity: binary_sensor.room_occupancy
from: "off"
to: "on"
action_path: choose/0/sequence/0
This sanitized example shows two independent triggers reaching the same action 245 milliseconds apart. The evidence points to overlapping motion and occupancy logic, not a Home Assistant scheduler that randomly duplicated one run. Replace real entity names and timestamps when sharing logs publicly.
Common duplicate-run patterns
At Home Assistant startup: An automation may have a Home Assistant start trigger while the same entities also restore or update their state. Compare trigger IDs. If both paths are intentional, decide whether startup should initialize state silently or perform the normal outward action. Avoid sending duplicate alerts simply because several entities become available together.
At sunrise, sunset or a scheduled minute: A time trigger can overlap with a sun, schedule or template trigger that becomes true at nearly the same moment. Use one clock source for the action or branch explicitly so the fallback does not duplicate the primary trigger.
After an automation reload: Reloading attaches the current trigger definitions. It should not be treated as a routine cure for duplicates. If behavior changes only after reload, inspect whether YAML and UI definitions differ, whether a custom integration registers listeners correctly, and whether the issue returns after the next edit or restart.
After reconnecting MQTT or another event source: A retained message, restored entity state or publisher retry can reproduce an apparently old condition. Compare message payloads and source timestamps rather than assuming the automation engine replayed a run. Do not delete retained messages globally; identify the topic and publisher first.
Only when actions take a long time: This pattern makes concurrency mode relevant. If a second trigger arrives while the first sequence is waiting, mode parallel may create two active paths, queued may preserve both, restart may abandon the first, and single may reject the second. Choose the mode that matches the intended physical behavior and include timeouts for waits that could otherwise remain open.
Do not create a fragile cooldown
A cooldown helper can be appropriate for a genuinely noisy source, but it must have a defined duration and consequence. A five-second lockout that hides a duplicate door event could also suppress a real reopen. Before adding one, measure the duplicate interval from traces, decide the fastest legitimate repeat, and choose a guard narrower than that legitimate behavior.
For notifications, consider whether the message can be keyed to an event ID or state transition. For counters and paid API calls, verify that a repeated request cannot create financial or operational harm. For locks, covers, garage doors and alarms, prefer fixing the source and adding explicit safety conditions over relying on a timer.
Safest repair sequence
- Create a current backup before editing important automations.
- Capture the two traces and identify whether there are two runs or one run with two actions.
- Assign trigger IDs if the automation has multiple triggers.
- Narrow state triggers with explicit to/from values where that matches the intent.
- Search for duplicate automations and other parents calling the same script or service.
- Change one cause only. Reload automations if you edited YAML; do not restart the whole host unless required.
- Trigger one controlled test and inspect the new trace.
- Test again after the source has been idle long enough to reproduce the original condition.
- Verify the physical outcome, notification count and Logbook entry.
- Record the final change and keep the evidence until the behavior remains stable.
Verification matrix
- Two traces, different trigger IDs: overlapping triggers; fix conditions or choose a source of truth.
- Two traces, same trigger ID: inspect bouncing state, repeated events, duplicate definitions or publisher retries.
- One trace, two action nodes: repair the action sequence, choose/repeat block or child script.
- One trace, one action call, device acts twice: investigate the integration, transport or device.
- No trace for one outcome: another automation, integration or external platform probably caused it.
Prevention
Name automations and scripts for the outcome they own. Use unique IDs, assign trigger IDs, avoid duplicating the same decision across UI and YAML, and keep high-impact actions centralized. Store enough traces to cover the diagnostic window without retaining unnecessary sensitive details. After Home Assistant or integration updates, test automations that send messages, unlock doors, operate covers, change climate settings or call paid APIs.
Use the automation-not-triggering guide when the opposite failure occurs. Sanitize evidence with the Troubliq Log Sanitizer, and use the Error Decoder for an exact message or warning.
When to escalate
Escalate when two traces show one integration producing reproducible duplicate events, when the trace data contradicts the documented mode behavior, or when duplication began immediately after a known update and persists in a minimal test. Include Home Assistant Core version, installation type, sanitized automation YAML, two traces, relevant integration version and the smallest reproduction. Do not publish secrets or an entire configuration archive.
Official sources and review record
Last reviewed September 29, 2026. Photo credit: Luke Chesser via Unsplash.