Theom
11/16/2025, 7:40 AMparent_flow_run_id? Below is the current trigger json:
{
"type": "event",
"match": {
"prefect.resource.id": "prefect.flow-run.*"
},
"match_related": {
"prefect.resource.id": [
"prefect.deployment.<deployment1-id>",
"prefect.deployment.<deployment2-id>"
],
"prefect.resource.role": "deployment"
},
"after": [],
"expect": [
"prefect.flow-run.Completed",
"prefect.flow-run.Cached"
],
"for_each": [
"prefect.resource.id"
],
"posture": "Reactive",
"threshold": 1,
"within": 0
}Marvin
11/16/2025, 7:40 AMMarvin
11/16/2025, 7:49 AMmatch and match_related. There’s no NOT/EXISTS operator and no generic “where” filter.
- While a subflow’s flow run does have parent_task_run_id in the database, that field is not exposed as a filterable event label, so you can’t exclude subflows by checking it in a trigger.
- Docs for reference: Event triggers and REST API: Flow runs.
Workable patterns you can use instead:
1) Emit a custom event only for top‑level runs and trigger on that
- At the end of your flow, check if it’s a root run (no parent) and emit a custom event.
- Point your automation at that event name instead of prefect.flow-run.Completed.
Example flow snippet:
from prefect import flow, get_run_context
from prefect.events import emit_event
@flow
def my_flow():
# ... your logic ...
# Emit only for top-level runs
ctx = get_run_context()
if getattr(ctx.flow_run, "parent_task_run_id", None) is None:
related = []
if getattr(ctx.flow_run, "deployment_id", None):
related.append({
"prefect.resource.id": f"prefect.deployment.{ctx.flow_run.deployment_id}",
"prefect.resource.role": "deployment",
})
emit_event(
event="my-org.flow-run.top-level-completed",
resource={"prefect.resource.id": f"prefect.flow-run.{ctx.flow_run.id}"},
related=related,
)
Updated automation trigger (listen for your custom event while still scoping to your deployments):
{
"type": "event",
"match": {
"prefect.resource.id": "prefect.flow-run.*"
},
"match_related": {
"prefect.resource.id": [
"prefect.deployment.<deployment1-id>",
"prefect.deployment<deployment2-id>"
],
"prefect.resource.role": "deployment"
},
"after": [],
"expect": [
"my-org.flow-run.top-level-completed"
],
"for_each": [
"prefect.resource.id"
],
"posture": "Reactive",
"threshold": 1,
"within": 0
}
2) Use tags to distinguish top-level vs. subflow runs
- If your subflows run via a different deployment, you can tag only the top-level deployment (e.g., tag “top-level”) and filter on prefect.tag.top-level in match_related.
- Caveat: if subflows use the exact same deployment, tags won’t help because they’ll be identical.
A quick sanity check: how are your subflows started?
- If you call a child @flow function directly (not via run_deployment), those child runs won’t be associated with a deployment. With your current trigger (which filters by deployment), those subflow runs should already be excluded.
- If you launch subflows using run_deployment (i.e., child runs are tied to the same deployments), then use approach #1 (custom event) to cleanly separate top-level from subflows.
If you’d like, I can file a feature request to support NOT/EXISTS conditions (e.g., “no related task run” or “no parent_task_run_id”) in automation filters.Theom
11/16/2025, 7:59 AMMarvin
11/16/2025, 7:59 AMMarvin
11/16/2025, 7:59 AMmatch and match_related.
- There’s no operator for NOT/EXISTS and no way to match “None”/missing fields (e.g., you can’t filter on parent_task_run_id is None or “no related task-run”).
Docs: Event triggers
If you want, I can help you implement the custom-event workaround (emit a special event only for top-level runs) or file a feature request for null/negation filters.Theom
11/16/2025, 8:07 AMrun_deployment . But I guess here again I can't act on a tag not being present right? Is there no "expect_not" key?Marvin
11/16/2025, 8:08 AMMarvin
11/16/2025, 8:11 AMtop-level
- Ensure subflow runs do not include that tag
- Make your automation require that tag
Example trigger JSON (adding a tag requirement to your existing deployment scope):
{
"type": "event",
"match": {
"prefect.resource.id": "prefect.flow-run.*"
},
"match_related": [
{
"prefect.resource.id": [
"prefect.deployment.<deployment1-id>",
"prefect.deployment.<deployment2-id>"
],
"prefect.resource.role": "deployment"
},
{
"prefect.resource.id": "prefect.tag.top-level"
}
],
"after": [],
"expect": [
"prefect.flow-run.Completed",
"prefect.flow-run.Cached"
],
"for_each": [
"prefect.resource.id"
],
"posture": "Reactive",
"threshold": 1,
"within": 0
}
Important caveat with tags:
- If subflows are launched with run_deployment against the same deployment as your top-level runs and that deployment has default tags, those tags will typically be included on subflow runs too. In that case, requiring a “top-level” tag won’t distinguish them.
- If you can’t ensure a tag that is present only on top-level runs (e.g., by using a separate deployment for top-level, or by only adding the tag when creating the top-level run), this tag-based approach won’t reliably exclude subflows.
What you can do:
- If you can add tags only when calling run_deployment: add a “subflow” tag to child runs, but don’t rely on the absence of that tag in the trigger. Instead, arrange for top-level runs to include a distinct “top-level” tag (e.g., via a separate deployment for top-level runs or by explicitly adding tags when you create top-level runs).
- If you cannot guarantee a top-level-only tag, use the custom-event approach from earlier; it’s the most reliable way to separate top-level from subflows today.
Docs: Event triggersTheom
11/16/2025, 8:33 AMMarvin
11/16/2025, 8:33 AMMarvin
11/16/2025, 8:34 AMtop-level tag via match_related. Note the array form so both related conditions must be satisfied (deployment AND tag):
{
"type": "event",
"match": {
"prefect.resource.id": "prefect.flow-run.*"
},
"match_related": [
{
"prefect.resource.id": [
"prefect.deployment.<deployment1-id>",
"prefect.deployment.<deployment2-id>"
],
"prefect.resource.role": "deployment"
},
{
"prefect.resource.id": "prefect.tag.top-level"
}
],
"after": [],
"expect": [
"prefect.flow-run.Completed",
"prefect.flow-run.Cached"
],
"for_each": [
"prefect.resource.id"
],
"posture": "Reactive",
"threshold": 1,
"within": 0
}
Make sure your top-level runs include the top-level tag (and subflows do not).