<@ULVA73B9P> I am trying to find the originating s...
# ask-marvin
f
@Marvin I am trying to find the originating source of an automation by looking at events. I have a flow in a deployment that is started by an automation. The automation is started based on a custom event. The deployment fails, and when tracing back to the origin I seem to hit a dead end with the automation event
prefect-cloud.automation.action.triggered
How can I trace back to the originating event?
m
thought for 546.5 seconds
Great question — you’re very close! In Prefect 3.x, the key to tracing an automation back to the original event is the event’s causal link via the
follows
field. What to look for -
prefect-cloud.automation.action.triggered
should include a
follows
UUID. That UUID is the ID of the event that matched your automation’s trigger (your custom event). - If you keep following
follows
values, you can walk the chain backward until you reach the originating event with no
follows
. How to trace it Option A — In the Prefect Cloud UI 1. Open the event details for the
prefect-cloud.automation.action.triggered
event. 2. Copy the value of
follows
(if present). 3. Search the Events feed for that event ID. That should be your original custom event (or another preceding system event if there are multiple steps). 4. Repeat if needed until you reach the event with no
follows
. Option B — With the Events API / Python You can query the events API and walk the chain:
Copy code
import asyncio
from prefect.events import get_events_client
from prefect.events.filters import EventFilter, EventNameFilter, EventIDFilter

async def find_originating_event():
    client = get_events_client()

    # 1) Find your automation action event(s)
    action_page = await client.read_events(
        filter=EventFilter(
            name=EventNameFilter(any_=["prefect-cloud.automation.action.triggered"])
        )
    )
    action_event = action_page.events[0]  # or select the specific one by time/labels

    # 2) Follow the chain backwards
    current = action_event
    chain = [current]
    while current.follows:
        prev_page = await client.read_events(
            filter=EventFilter(id=EventIDFilter(any_=[str(current.follows)]))
        )
        if not prev_page.events:
            break
        current = prev_page.events[0]
        chain.append(current)

    # The last item in `chain` is the originating event
    return list(reversed(chain))

origin_chain = asyncio.run(find_originating_event())
for evt in origin_chain:
    print(evt.event, evt.id, evt.follows)
Notes and edge cases - If
follows
is missing on the automation action event: This usually means the system could not attach causal ordering (e.g., timing edge cases). In that case: - Use the Events UI or API to search for events just before the action event’s
occurred
time that match your automation’s trigger criteria. - Filter by related resources. The automation action event will include related resources (e.g., the automation itself, deployment) in `related`; you can search the event feed for your custom event around the same time window. - The
related
resources on
prefect-cloud.automation.action.triggered
will point to things like the automation and the target deployment/flow, but not the triggering event itself —
follows
is the primary causal link to the triggering event. - If you’re frequently correlating events, consider adding a correlation label to your custom events (e.g.,
correlation_id
) and using the same label in downstream emissions; this makes filtering and tracing trivial. Helpful docs - Events concepts - Event triggers and automations - Events API (read events) - Event schema (ReceivedEvent, follows) If you can share a screenshot or the JSON for the
prefect-cloud.automation.action.triggered
event (with IDs redacted if needed), I can point out exactly where to grab the
follows
and help you trace it in your workspace.
f
@Marvin Yes, there is not any "follows" key there. I have never seen that. what is wrong?
m
thought for 76.0 seconds
You’re not doing anything wrong. In Prefect 3.x, the
follows
field is optional and many system-generated events (including automation action events) do not set it. So it’s expected that
prefect-cloud.automation.action.triggered
does not include a
follows
pointer to the originating event today. How to trace without follows UI - Go to your automation in the Cloud UI, check the Activity/History entry that corresponds to when your flow run was started. That view shows details of the firing, including the triggering event info; from there you can jump to the Events feed around that time. API/Python - Search for the triggering custom event by time and trigger criteria. A common pattern is to: 1) find the automation action event and grab its
occurred
timestamp 2) query the events in a small time window before that time using the custom event name(s) and any label criteria your trigger uses Example:
Copy code
import asyncio
from datetime import timedelta
from prefect.events import get_events_client
from prefect.events.filters import EventFilter, EventNameFilter, EventOccurredFilter, EventIDFilter

async def find_triggering_custom_event(action_event_id, custom_event_names):
    client = get_events_client()

    # 1) Get the automation action event by id
    action_page = await client.read_events(
        filter=EventFilter(id=EventIDFilter(any_=[action_event_id]))
    )
    if not action_page.events:
        raise RuntimeError("Action event not found")
    action_event = action_page.events[0]

    # 2) Search for your custom event shortly before the action event
    window = timedelta(minutes=5)
    custom_page = await client.read_events(
        filter=EventFilter(
            name=EventNameFilter(any_=custom_event_names),
            occurred=EventOccurredFilter(
                after=action_event.occurred - window,
                before=action_event.occurred + timedelta(seconds=5),
            ),
        )
    )

    # Heuristic: the latest matching custom event before the action is likely the trigger
    candidates = [e for e in custom_page.events if e.occurred <= action_event.occurred]
    candidates.sort(key=lambda e: e.occurred, reverse=True)
    return candidates[0] if candidates else None

# usage:
# triggering = asyncio.run(find_triggering_custom_event("<automation_action_event_id>", ["myapp.custom.event"]))
# print(triggering)
Tips that make this easier - Add a correlation label to your custom event (e.g.,
correlation_id
) and carry it forward in downstream emissions. Then you can filter by that label directly. - Align your time window to how quickly your automations fire; 1–5 minutes before the action event usually works well. - Match on both event name and key labels used in your trigger to reduce noise. If you can share: - the automation name/id, - the exact custom event name (or pattern) the trigger listens to, - and the timestamp/ID of the
prefect-cloud.automation.action.triggered
event, I can give you a concrete query or walk it with you. Would you like me to open a feature request to include an explicit link from
prefect-cloud.automation.action.triggered
back to the triggering event? That would make this a one-click trace in the future.
f
@Marvin yes, I would like that
m
thought for 26.4 seconds
Awesome — I’ve created a feature request to add a direct link from automation action events back to the triggering event so you can trace the origin with one click. Discussion: Feature request: Link automation action events to triggering events Summary of the ask - Add a causal reference from
prefect-cloud.automation.action.triggered
to the triggering event via: - setting
follows
to the triggering event ID, or - including
payload.triggering_event_id
, or - adding a related resource role like
triggering_event
- Surface this in the UI with a “View triggering event” link. If you have additional context or examples from your workspace (redacted is fine), feel free to add them to the thread — it will help prioritize and design the best solution.