Skip to main content
Version: 3.0 (next)

Pipeline Event Trigger Node

Overview​

The Pipeline Event Trigger Node automatically initiates a MaestroHub pipeline when another pipeline finishes execution with a matching status. This enables chaining workflows—for example, running a cleanup pipeline after a data-import pipeline completes, or triggering an alert pipeline when a critical workflow fails. Built-in chain-depth tracking and self-trigger prevention ensure that cascading pipelines cannot create infinite loops.


Core Functionality​

What It Does​

1. Cross-Pipeline Automation Start pipelines automatically when one or more watched pipelines reach a specified execution status—without manual intervention, polling, or external schedulers.

2. Status-Based Filtering Subscribe to specific execution outcomes: completed, failed, completed_with_errors, cancelled, or the wildcard any to match all terminal statuses.

3. Chain-Depth Tracking Every execution triggered by a Pipeline Event Trigger carries a chain_depth counter. When a triggered pipeline itself has a Pipeline Event Trigger, the depth increments. A chain stops after three event-triggered runs in a row, which prevents runaway loops.

4. Self-Trigger Prevention A pipeline cannot watch itself. This is enforced at the domain level during pipeline validation, ensuring that a pipeline's own execution events never re-trigger the same pipeline.

5. Multi-Pipeline Watching A single trigger can monitor multiple source pipelines. When any of the watched pipelines finishes with a matching status, the trigger fires.


Chain Depth & Loop Prevention​

How Chain Depth Works​

Chain depth tracks how many Pipeline Event Triggers have fired in sequence:

  1. Depth 0: A pipeline runs via manual, schedule, webhook, or any non-pipeline-event trigger
  2. Depth 1: A Pipeline Event Trigger fires in response to the depth-0 execution
  3. Depth 2: Another Pipeline Event Trigger fires in response to the depth-1 execution
  4. Depth 3: A third Pipeline Event Trigger fires in response to the depth-2 execution

When a depth-3 execution finishes, a Pipeline Event Trigger watching it does not fire. The event is dropped and a warning is logged.

The limit is the trigger's maxChainDepth. The designer has no control for it and always saves 3. A pipeline created or edited through the API or MCP can set a lower value (1–3) — see the Configuration reference.

Example​

Pipeline A (manual run, depth 0)
└─ triggers Pipeline B (depth 1)
└─ triggers Pipeline C (depth 2)
└─ triggers Pipeline D (depth 3)
└─ a trigger watching D would start depth 4 → BLOCKED

Safety Guarantees​

ProtectionMechanism
Self-triggerDomain validation rejects a pipeline that watches itself
Infinite chainsChain depth counter compared against maxChainDepth (3 from the designer)
Missing depth metadataDefaults to depth 0 if metadata is absent
Chain Depth Limits

A chain can run at most three event-triggered pipelines in a row. Design your pipeline chains to complete meaningful work within this limit. If you need deeper orchestration, consider using a single coordinator pipeline that triggers each step sequentially.


Configuration Options​

Basic Information​

FieldTypeDescription
Node LabelString (Required)Display name for the node on the pipeline canvas. Must be non-empty (trimmed).
DescriptionString (Optional)Explains what this trigger monitors and initiates.

Parameters​

The trigger configuration is organized across two tabs in the UI: Parameters and Settings.

ParameterTypeDefaultRequiredConstraintsDescription
Watched Pipelinesstring[][]YesAt least 1 pipeline; cannot include the current pipelinePipelines whose execution events trigger this pipeline.
Watched Statusesstring[][]YesAt least 1 status from the allowed setExecution statuses that trigger this pipeline.
EnabledbooleantrueNo--Enable/disable the trigger.

Watched Statuses​

StatusDescription
completedPipeline finished successfully—all nodes passed.
failedPipeline stopped due to a node failure (after retries exhausted).
completed_with_errorsPipeline finished but some nodes encountered errors (with On Error set to continueExecution).
cancelledPipeline execution was manually or programmatically cancelled.
anyWildcard—matches all terminal statuses above.
A partial success is completed_with_errors, not completed

A run in which a node failed but the pipeline was set to Continue Execution ends as completed_with_errors. A trigger that watches only completed does not fire for it, and one that watches only failed does not either. Watch completed_with_errors explicitly, or use any, if the chained pipeline should also run after a partial success. See Run status and On Error.

Self-Trigger Prevention

The pipeline selector in the UI automatically excludes the current pipeline from the list. At the backend, domain validation also rejects a pipeline that includes its own ID in watchedPipelineIds.


Settings​

Description

A free-text area for documenting the node's purpose and behavior. Notes entered here are saved with the pipeline and visible to all team members.

Execution Settings

SettingOptionsDefaultDescription
Timeout (seconds)numberPipeline defaultMaximum execution time for this node (1--600). Leave empty for pipeline default.
Retry on TimeoutPipeline Default / Enabled / DisabledPipeline DefaultWhether to retry the node if it times out.
Retry on FailPipeline Default / Enabled / DisabledPipeline DefaultWhether to retry on failure. When Enabled, shows Advanced Retry Configuration.
On ErrorPipeline Default / Stop Pipeline / Continue ExecutionPipeline DefaultBehavior when node fails after all retries.

Advanced Retry Configuration (visible when Retry on Fail = Enabled)

FieldTypeDefaultRangeDescription
Max Attemptsnumber31--10Maximum retry attempts.
Initial Delay (ms)number1000100--30,000Wait before first retry.
Max Delay (ms)number1200001,000--300,000Upper bound for backoff delay.
Multipliernumber2.01.0--5.0Exponential backoff multiplier.
Jitter Factornumber0.10--0.5Random jitter (+-percentage).

Output Data Structure​

When a watched pipeline finishes with a matching status, the trigger produces a structured output with two top-level keys: _metadata and result.

$trigger.result is the watched run, not this pipeline's result

Every node output in MaestroHub is the same { result, _metadata } envelope, so this trigger's payload lands under result like any other trigger's. Everything in it describes the source run that fired the trigger. When you need the source run's identity, prefer the unambiguous _metadata.source* keys (sourcePipelineName, sourceExecutionId, sourceStatus, sourcePipelineVersion); use result for the counts and the failed-node list.

Output Format​

{
"_metadata": {
"type": "pipeline_event_trigger",
"sourcePipelineId": "bf29be94-fc0a-4dc4-8e5c-092f1b74eb4b",
"sourcePipelineName": "Daily Data Import",
"sourcePipelineVersion": 12,
"sourceExecutionId": "aef374c3-aa2b-454e-aabc-5657faac5950",
"sourceStatus": "completed_with_errors",
"sourceTriggerType": "schedule",
"sourceDuration": "2m15.3s",
"chainDepth": 1
},
"result": {
"executionId": "aef374c3-aa2b-454e-aabc-5657faac5950",
"pipelineId": "bf29be94-fc0a-4dc4-8e5c-092f1b74eb4b",
"pipelineName": "Daily Data Import",
"pipelineVersion": 12,
"status": "completed_with_errors",
"duration": "2m15.3s",
"nodeCount": 8,
"successCount": 7,
"failureCount": 1,
"skippedCount": 0,
"triggerType": "schedule",
"errors": [
{
"nodeId": "node-1726000000000-ab3k9x2qz",
"nodeName": "Parse Orders",
"nodeType": "logic.javascript",
"errorMessage": "javascript execution failed: TypeError: cannot read 'sku' of undefined",
"errorCode": "SCRIPT_ERROR",
"errorCategory": "permanent",
"attemptCount": 1
}
]
}
}

A run with no failed node carries "errors": null. Guard on result.failureCount, not on the array's length.

_metadata Fields​

FieldTypeDescription
typestringAlways "pipeline_event_trigger".
sourcePipelineIdstringUUID of the watched pipeline that completed.
sourcePipelineNamestringDisplay name of the source pipeline.
sourcePipelineVersionnumberVersion of the source pipeline that ran. Node names and wiring can change between versions; this is the version the summary below describes, and the one GET /pipelines/:id/versions/:version returns.
sourceExecutionIdstringUUID of the specific execution that triggered this event.
sourceStatusstringTerminal status of the source execution ("completed", "failed", "completed_with_errors", "cancelled").
sourceTriggerTypestringHow the source pipeline was started ("schedule", "webhook", "manual", ...). This pipeline's own trigger type is always pipeline_event.
sourceDurationstringTotal execution duration as a Go duration string (e.g., "2m15.3s", "500ms").
chainDepthnumberCurrent depth in the pipeline event chain (starts at 1 for the first triggered pipeline).

result Fields​

FieldTypeDescription
executionIdstringUUID of the source execution (same as _metadata.sourceExecutionId).
pipelineIdstringUUID of the source pipeline (same as _metadata.sourcePipelineId).
pipelineNamestringDisplay name of the source pipeline.
pipelineVersionnumberVersion of the source pipeline that ran (same as _metadata.sourcePipelineVersion).
statusstringTerminal status of the source execution.
durationstringTotal execution duration as a Go duration string.
nodeCountnumberTotal number of nodes in the source pipeline.
successCountnumberNumber of nodes that completed successfully.
failureCountnumberNumber of nodes that failed.
skippedCountnumberNumber of nodes that were skipped.
triggerTypestringHow the source pipeline was originally triggered (same as _metadata.sourceTriggerType). Not this pipeline's trigger type.
errorsarray | nullOne entry per failed node, described below. null when no node failed. Nodes that failed under On Error: Continue Execution are included; skipped and cancelled nodes are not.

result.errors[] Fields​

FieldTypeDescription
nodeIdstringThe node's id. Stable for the life of the node and unique in the pipeline — use it to key on, correlate, or look the node up.
nodeNamestringThe node's display name as of the version that ran — the $node["Name"] key an author uses. Meant for humans: put it in alert text. Names are not unique, so never branch on it.
nodeTypestringThe node type, e.g. logic.javascript, connected.postgres.write.
errorMessagestringThe error the node recorded.
errorCodestringThe classified code when the executor set one, e.g. CONN_TIMEOUT; SCRIPT_ERROR when the node's own JavaScript or expression threw, failed to evaluate or did not compile (TIMEOUT when it ran past the node's timeout); UNKNOWN_ERROR otherwise.
errorCategorystringtransient, permanent or timeout.
attemptCountnumberAttempts made, including retries.

Referencing in Downstream Nodes​

Use expressions to access pipeline event data in subsequent nodes:

  • $trigger._metadata.type -- always "pipeline_event_trigger"
  • $trigger._metadata.sourcePipelineId -- UUID of the source pipeline
  • $trigger._metadata.sourcePipelineName -- name of the source pipeline
  • $trigger._metadata.sourcePipelineVersion -- version of the source pipeline that ran
  • $trigger._metadata.sourceExecutionId -- UUID of the source execution
  • $trigger._metadata.sourceStatus -- terminal status ("completed", "failed", etc.)
  • $trigger._metadata.sourceTriggerType -- how the source pipeline was started
  • $trigger._metadata.sourceDuration -- execution duration string
  • $trigger._metadata.chainDepth -- current chain depth
  • $trigger.result.nodeCount -- total nodes in the source pipeline
  • $trigger.result.successCount -- nodes that succeeded
  • $trigger.result.failureCount -- nodes that failed
  • $trigger.result.skippedCount -- nodes that were skipped
  • $trigger.result.triggerType -- how the source pipeline was triggered
  • $trigger.result.errors -- the failed nodes (null when none), each with nodeId, nodeName, errorMessage, ...
Naming the failed node in an alert

Ids minted by the designer look like node-1726000000000-ab3k9x2qz, so an alert built from nodeId tells nobody anything. Use nodeName for the text and keep nodeId for anything a machine compares:

if ($trigger.result.failureCount > 0) {
const e = $trigger.result.errors[0];
return {
text: `${$trigger._metadata.sourcePipelineName} failed at "${e.nodeName}": ${e.errorMessage}`,
nodeId: e.nodeId,
executionId: $trigger._metadata.sourceExecutionId,
};
}

Validation Rules​

Parameter Validation​

Node Label

  • Must not be empty
  • Must not consist only of whitespace
  • Error: "Node name is required"

Watched Pipeline IDs

  • Must be provided and non-empty
  • Must contain at least one pipeline ID
  • Cannot include the current pipeline's own ID (self-trigger prevention)
  • Each ID must be a valid UUID referencing an existing pipeline
  • Error: "At least one pipeline must be selected"
  • Error: "Pipeline cannot watch itself"

Watched Statuses

  • Must be provided and non-empty
  • Must contain at least one status
  • Each status must be one of: completed, failed, completed_with_errors, cancelled, any
  • Error: "At least one status must be selected"
  • Error: "Invalid status: must be one of completed, failed, completed_with_errors, cancelled, any"

Max Chain Depth (maxChainDepth, API and MCP only)

  • Must be a whole number between 1 and 3 (inclusive)

Enabled Flag

  • Must be a boolean if provided
  • Error: "Enabled must be a boolean value"

Usage Examples​

Post-Import Cleanup​

Key configuration

  • Label: Post-Import Cleanup
  • Watched Pipelines: Daily Data Import
  • Watched Statuses: completed
  • Enabled: true
  • Settings: retry disabled, on error stop

Downstream usage: $trigger._metadata.sourceExecutionId to correlate with the import execution, $trigger.result.nodeCount and $trigger.result.successCount to verify all import steps ran.

Failure Alert Pipeline​

Key configuration

  • Label: Critical Pipeline Failure Alert
  • Watched Pipelines: Payment Processor, Order Fulfillment, Inventory Sync
  • Watched Statuses: failed, completed_with_errors
  • Enabled: true
  • Settings: retry enabled, on error continue

Downstream usage: $trigger._metadata.sourcePipelineName to identify which pipeline failed, $trigger.result.errors[0].nodeName and .errorMessage to say where and why in the alert, $trigger._metadata.sourceTriggerType to understand the original trigger context.

Cascading ETL Pipeline​

Key configuration

  • Label: Transform After Extract
  • Watched Pipelines: Data Extraction Pipeline
  • Watched Statuses: completed
  • Enabled: true
  • Settings: retry disabled, on error stop

Downstream usage: $trigger._metadata.chainDepth to track position in the ETL chain, $trigger.result.duration to log extraction time, $trigger._metadata.sourceStatus to confirm successful extraction before transforming.

Audit Logging​

Key configuration

  • Label: Execution Audit Logger
  • Watched Pipelines: All critical business pipelines
  • Watched Statuses: any
  • Enabled: true
  • Settings: retry enabled, on error continue

Downstream usage: Log $trigger.result.pipelineName, $trigger.result.status, $trigger.result.duration, $trigger.result.nodeCount, $trigger.result.successCount, $trigger.result.failureCount, and $trigger.result.skippedCount to an audit database for compliance tracking.


Best Practices​

Designing Pipeline Chains​

PracticeRationale
Keep chains shortMost workflows need one or two hops; use all three only when each stage does distinct, necessary work
Use a coordinator patternFor deep orchestration, have one pipeline that triggers each step via webhooks or schedules
Avoid circular dependenciesEven though self-trigger is blocked, A → B → A is possible; the chain depth limit stops it after three hops
Document chain relationshipsUse the Settings description to note which pipelines watch this one

Status Selection​

  • Use completed for success-dependent workflows (ETL chains, post-processing)
  • Use failed or completed_with_errors for alerting and remediation pipelines
  • Use any sparingly—primarily for audit logging or monitoring dashboards
  • Combine statuses when a single response pipeline handles multiple outcomes

Error Handling Strategies​

For Critical Chains:

  • Set On Error to stopPipeline on the triggered pipeline
  • Watch for failed status on the triggered pipeline with a separate alert pipeline
  • Use $trigger.result.errors to propagate error context through the chain

For Best-Effort Workflows:

  • Set On Error to continueExecution
  • Use $trigger.result.failureCount to detect partial failures
  • Log results for later analysis without blocking the chain

Performance Considerations​

ScenarioRecommendation
High-frequency source pipelinesEnsure downstream pipelines complete before the next trigger fires to avoid queue buildup
Many watchers on one pipelineEach watcher creates an independent execution; monitor total throughput
Long-running triggered pipelinesSet appropriate timeouts; consider whether the source pipeline's next run will re-trigger
Deep chains with parallel watchersCan create exponential fan-out; map the full chain before deploying

Enable vs. Disable​

  • Use the trigger's Enabled parameter to temporarily pause event-driven chaining without modifying pipeline configuration
  • Disable triggers during maintenance on source pipelines to prevent cascading failures
  • Document the reason for disabled triggers in the node's Notes field
  • Re-enable triggers only after verifying source pipelines are stable

Configuration reference​

The fields below are generated from the node's config contract, so they match what the pipeline validator enforces and what the designer's form offers.

trigger.pipeline.event​

FieldTypeRequiredDefaultValuesDescription
watchedPipelineIdsstring[]yes——Ids of the pipelines whose execution end should start this one, e.g. ["4f2c…"]; at least one, and not this pipeline itself
watchedStatusesstring[]yes—completed, failed, completed_with_errors, cancelled, anyExecution statuses of a watched pipeline that fire this trigger, e.g. ["completed", "failed"]; any matches every terminal status. At least one
maxChainDepthintegerno31–3How many pipeline-event triggers may fire in a row before this one stops the chain, 1 to 3 (default 3): a run started by a manual, schedule or webhook trigger is depth 0, each event-triggered run adds one. Guards against A→B→A loops
enabledbooleannotrue—false pauses this trigger without deleting it: the watched pipelines are not subscribed and nothing fires. Default true
testDataanyno——Event payload the designer's sandbox (Test) run pretends to receive, read downstream as $trigger.result exactly as a real event would be. Unused in production