How to Build a Centralized Error-Notification Subworkflow Every Workflow Can Call
Build one reusable Subworkflow in Spojit that takes a failure payload, has an agent summarize the likely cause, then posts a Slack alert and sends an email so every other workflow reports errors in exactly the same way.
What This Integration Does
When you run many workflows, each one tends to grow its own ad-hoc way of reporting problems: a Slack message here, an email there, slightly different wording everywhere. That makes incidents hard to triage because the alerts never look the same. This tutorial builds a single error-notification workflow that you wrap in a Subworkflow node. Any other workflow can call it with a small failure payload, and the shared workflow does the rest: it asks an agent to summarize the cause in plain language, posts a consistently formatted alert to a Slack channel, and emails the on-call owner. Change the format once, and every caller benefits immediately.
The notifier runs as a child workflow. A parent workflow calls it from a Subworkflow node, passing in data such as the workflow name, the step that failed, and the raw error text. The child starts from its own Manual trigger, reshapes the input, runs an Connector node in Agent mode to produce a short structured summary, and fans the result out to Slack and email. Its final output (the summary plus the Slack and email send results) returns to the parent. Because children appear as their own execution-history entries, you can open any notification run on its own to see exactly what was sent. Re-running the parent re-invokes the child cleanly: the notifier holds no state between runs, so each call is independent.
Prerequisites
- A Slack connection with permission to post to your alerts channel (used by the
send-messagetool). See the Slack connector reference. - A verified Resend connection so alert emails can be sent from your own domain (used by the
send-emailtool). See the Resend connector reference. - The Slack channel ID or name you want alerts in (for example
#ops-alerts), and the email address of whoever should receive failure notices. - Familiarity with how Subworkflow nodes pass data between a parent and a child.
- Optional: an AI model selected for Agent mode so the summary step can run. This consumes AI credits.
Step 1: Create the notifier workflow with a Manual trigger
Create a new workflow named something clear like Error Notifier. Give it a Trigger node of type Manual. The Manual trigger's output is whatever request body the caller passes in, which is exactly how a Subworkflow node feeds data to a child. Decide on a stable input shape now so every caller sends the same fields. A good contract is:
{
"workflowName": "Shopify to NetSuite Sync",
"failedStep": "create-record (NetSuite)",
"errorMessage": "Request failed with status 429: rate limit exceeded",
"executionId": "exec_8f12...",
"severity": "high",
"ownerEmail": "ops@yourcompany.com"
}
Inside the notifier you reference these as {{ input.workflowName }}, {{ input.errorMessage }}, and so on. Keep the payload small: pass identifiers and the error text, not large objects.
Step 2: Normalize the payload with a Transform node
Add a Transform node right after the trigger so the rest of the workflow never has to deal with missing fields. Use it to fill defaults and build a single human-readable title. For example, default severity to normal when absent, and assemble a title like [high] Shopify to NetSuite Sync failed at create-record (NetSuite). Output the normalized object to a variable such as incident so later nodes can read {{ incident.title }}, {{ incident.severity }}, and {{ incident.errorMessage }}. This step is also where you truncate an over-long error string before it reaches the agent, which keeps AI cost predictable.
Step 3: Summarize the cause with a Connector node in Agent mode
Add a Connector node and switch it to Agent mode. Agent mode lets you describe the task in a prompt and force a clean JSON result with a Response Schema, which is what you want here: a short, consistent summary rather than free-form prose. Point the prompt at the normalized incident and ask for a one-line cause and a suggested next action. Use a prompt like:
You are triaging a failed automation run. Summarize the likely cause in one
sentence and suggest one concrete next step. Be specific and non-technical.
Workflow: {{ incident.workflowName }}
Failed step: {{ incident.failedStep }}
Severity: {{ incident.severity }}
Error: {{ incident.errorMessage }}
Set a Response Schema so the output is structured, for example fields summary, likelyCause, and suggestedAction. Save the result to a variable like triage. Downstream you then reference {{ triage.summary }} and {{ triage.suggestedAction }}. This is the only step that consumes AI credits, and it is where Miraxa, the intelligent layer across your automation, turns a raw error string into something an on-call person can act on. If you would rather skip AI entirely, you can remove this node and post the raw error directly, but the summary is what makes the alert genuinely useful.
Step 4: Post a Slack alert with the Slack connector
Add a Connector node in Direct mode, choose your Slack connection, and select the send-message tool. Direct mode is right here because there is exactly one deterministic call to make and no judgment needed, so it costs no AI credits. Map the channel to your alerts channel and build the message from the normalized incident and the triage summary. A clear message body looks like:
:rotating_light: {{ incident.title }}
Cause: {{ triage.likelyCause }}
Summary: {{ triage.summary }}
Next step: {{ triage.suggestedAction }}
Run: {{ incident.executionId }}
Because every caller routes through this single node, the format stays identical across all your workflows. If you want failures of different severities to land in different channels, add a Condition node before this step that branches on {{ incident.severity }} and points each branch at its own Slack node.
Step 5: Send the email alert with the Resend connector
Add another Connector node in Direct mode, choose your Resend connection, and select the send-email tool. Resend sends from your own verified domain, which is the right choice for an alert that should come from a recognizable address. Map the recipient to {{ incident.ownerEmail }}, set a subject like {{ incident.title }}, and reuse the same triage fields in the body so the email and the Slack alert tell the same story. If you only need a plain internal notice and do not need a custom from-address, you can instead use a Send Email node, which uses Spojit's built-in mail service and needs no connection; just remember external recipients must be on your org allowlist under Settings -> General -> Email recipients.
Step 6: Run Slack and email together, then call the notifier from your other workflows
To shave a little time off each alert, wrap the Slack node and the email node in a Parallel node so both branches send at once instead of waiting in sequence. After both branches finish, let the workflow end; its final output (the triage summary plus the two send results) is what returns to any parent. Now wire it up from a real workflow: in any workflow where you want consistent error reporting, add a Subworkflow node at the point where you detect a failure, pick Error Notifier as the Workflow, and set its Input to the agreed payload:
{
"workflowName": "Shopify to NetSuite Sync",
"failedStep": "create-record (NetSuite)",
"errorMessage": "{{ netsuite_result.error }}",
"executionId": "{{ trigger.executionId }}",
"severity": "high",
"ownerEmail": "ops@yourcompany.com"
}
Every workflow that adopts this pattern now reports errors the same way. To improve the format later, edit only Error Notifier; the change takes effect immediately for all parents.
Tips
- Keep the input contract small and stable. Passing identifiers and a trimmed error string keeps Agent-mode cost low and avoids breaking callers when you tweak the notifier internally.
- Use a Condition node on
{{ incident.severity }}to route high-severity failures to a noisier channel and lower ones to a quiet log channel, all without changing any caller. - Pin the same wording in the Slack body and the email body by reading them from the one
triagevariable, so the two channels never drift apart. - Ask Miraxa to scaffold the notifier for you with a prompt like "Build a workflow with a Manual trigger, a Transform node, a Connector node in Agent mode that summarizes an error, then a Parallel node with a Slack send-message node and a Resend send-email node," then fine-tune fields in the properties panel.
Common Pitfalls
- Calling the notifier from inside a failing branch only works if your workflow actually reaches that branch. Pair this with deliberate error handling so a failed step routes into the Subworkflow call rather than silently halting. See the guidance on retry and error handling.
- If the Slack
send-messagecall is rejected, confirm the connection can post to that specific channel and that the channel ID or name is correct; a private channel may need the connection invited first. - Resend will not deliver from an unverified domain. Verify your domain on the connection before relying on the
send-emailtool, or fall back to a Send Email node for internal-only alerts. - Avoid deep nesting. If a called child itself calls another notifier, you can create long chains that are hard to read in execution history. Keep the notifier one level deep.
- Only upstream variables resolve inside a node. The notifier cannot see the parent's workflow name or status automatically, which is exactly why you pass
workflowNameandseverityin the input payload.
Testing
Before wiring the notifier into production workflows, test it in isolation. Open Error Notifier, press Run on the Manual trigger, and paste a sample payload with a made-up errorMessage and your own address as ownerEmail. Confirm three things: the Slack alert lands in the expected channel with the formatted title, the email arrives from your Resend domain, and the agent summary reads sensibly. Check the run in execution history to verify the triage output looks right. Then test the full path by adding a Subworkflow node to one non-critical workflow, deliberately point it at a failing step, and confirm the child run shows up as its own history entry with the same output. Once one caller works end to end, roll the pattern out to the rest.