Skip to content

13. Troubleshooting

Look up the error message directly.


Start here

When something goes wrong, go to workflow detail → Overview → execution history and click the failed execution.

  • Which node is FAILED
  • What input that node received
  • What the output of the node right before it looked like

Those three usually reveal the cause.

A CANCELLED node is not the cause. It was merely cleaned up because another node failed. Look at the FAILED node.

A SKIPPED node is not the cause either. It is simply the branch a conditional did not take, and that is normal.


Errors when saving

At save time the graph structure is validated. Expressions are not.

workflow must have exactly one ENTRYPOINT

There is no start, or more than one. There has to be exactly one type: ENTRYPOINT node.

only JOINT nodes may have multiple inbound edges

Two or more edges lead into one node. Put a JOINT node there and gather them into it.

# ❌ two edges lead into notify
edges:
  - from: fetch-a
    to: notify
  - from: fetch-b
    to: notify

# ✅ route them through a JOINT
edges:
  - from: fetch-a
    to: join
  - from: fetch-b
    to: join
  - from: join
    to: notify

cycle detected

Following the arrows brings you back to where you started. Find the edge that leads backward and delete it. If you actually need repetition, use LOOP_START / LOOP_END.

edge references unknown node

An id written in an edge's from or to does not exist. Check for a typo in a node id.

duplicate node id

Two or more nodes share the same id. Node ids must be unique within a workflow.

condition label has no matching edge

Every label on a CONDITIONAL needs exactly one outgoing edge.

execution-info:
  conditions:
    - label: vip        # ← for this label
      expression: "${input.amount} >= 100000"

edges:
  - from: route
    to: vip-handler
    label: vip          # ← this edge is the match

LOOP_START has no matching LOOP_END

The two always come in pairs. Check that execution-info.loop-start on the LOOP_END holds the exact id of the matching LOOP_START.

LOOP_END ... multiple inbound edges (after branching inside a loop)

Putting a CONDITIONAL in a loop body is allowed. What you cannot do is wire the branches straight into LOOP_END — it takes exactly one incoming edge. Reconverge through a JOINT first, then connect that to LOOP_END. → Branching inside a loop

workflow has N nodes — the maximum is 200

Split the workflow up. You can chain them by having one workflow call another workflow's webhook with http_request.

It saves, but the slug conflicts

That id is already used within the workspace. Change to a different id, or edit the existing workflow.


Errors when running

ExpressionResolveException

The most common error. The path inside ${...} does not match the actual data.

In this order:

  1. Look at the actual output of the node right before it in the execution history.
  2. Compare your expression path against that shape.
  3. Check for a typo in the node id (${nodes.fetch-order...} versus the real id fetch-orders).

The usual suspects:

Wrong expression The problem
${nodes.join.response.body.x} A JOINT has no output. Reference the node before it
${nodes.trigger.response.body.windowStart} It only exists if the schedule trigger sets lookback
${secrets.MY_KEY} No secret by that name, or you registered it as a plain variable
${vars.MY_KEY} The reverse — you registered a secret and are calling it through vars
${item.id} Unusable outside a loop
${input.amount} The incoming edge has no request.data mapping

A value arrives as a strange string like {a=1, b=2}

You forgot | raw. It is required when passing an array or an object.

data: "${nodes.fetch.response.body.items}"          # ❌
data: "${nodes.fetch.response.body.items | raw}"    # ✅

→ Details

The Transform node fails

A CALL node's output has to be a JSON object. Emitting a bare array or number fails.

expression: "items[*].id"            # ❌ array
expression: "{ids: items[*].id}"     # ✅ wrap it in an object

expression: "length(items)"          # ❌ number
expression: "{count: length(items)}" # ✅

The branch always goes the same way (everything falls to otherwise)

There are two causes, and neither of them raises an error.

Cause 1 — the condition does not use ${input.*}. This is the common one.

expression: "${input.amount} >= 100000"   # ✅
expression: "amount >= 100000"            # ❌ compares the string "amount" to 100000 → always false

eeumsae splits the expression on the operator first, then resolves each side as an expression. A bare name with no ${...} is not a value — it is that name as literal text.

Cause 2 — the value the condition should see is not handed over. Add request.data to the incoming edge.

edges:
  - from: fetch
    to: route
    request:
      data:
        amount: "${nodes.fetch.response.body.totalAmount}"

Opening the route node's received input in the execution history shows immediately whether the value arrived.

Slack: not_in_channel

You did not invite the bot into the channel. In that channel:

/invite @eeumsae

Slack: channel_not_found

Either the channel ID is wrong or the channel is private. Find the channel ID in Slack by right-clicking the channel → View channel details → at the bottom. For a private channel, the bot has to be invited before it becomes visible.

Slack: invalid_auth

The connection expired or was revoked. Reconnect on the Connections screen.

LLM: 400 Bad Request

Two common causes.

  • temperature — some models, including recent Claude models, do not accept it. Try removing it.
  • A typo in model — check that the endpoint knows that model id.

LLM: 401 Unauthorized

The API key is wrong or expired. Check the value registered under ${secrets.*}. Also check that the key matches apiContract — calling ANTHROPIC_MESSAGES with an OpenAI key fails.

It fails with a timeout

Raise the timeout value, or narrow the query range. 30s – 2m works well for AI calls, and 30s – 1m for heavy lookup APIs.

The webhook is rejected with 409

The workflow is turned off. Flip the toggle on the list or detail screen. While it is off, schedules, webhooks and AI assistant runs are all blocked; only the Run button on screen gets through. → 10. Executions and Monitoring

The webhook is rejected — signature mismatch

If a WEBHOOK_SECRET secret exists in the workspace, every webhook requires a signature. The caller has to attach an X-Webhook-Signature header (or GitHub's X-Hub-Signature-256). → 03. Setting Up Triggers

If you never intended to use signatures, check the Variables screen for a secret registered under that name by mistake.

http_request fails on a 3xx

The response is a redirect that cannot be followed (no Location header, or 300 / 304). 301, 302, 303, 307 and 308 are followed automatically, so if you hit this, put the final URL in uri directly.

I narrowed the retries but timeouts are still retried

retry-on filters HTTP status and failure kind separately. Listing only statuses, as in retry-on: ["5xx"], leaves timeouts and connection errors fully retried. To narrow them, list a failure kind too: retry-on: ["5xx", "connect-error"] → 10. Executions and Monitoring

The workflow cannot be edited (MCP)

Something is running. Wait for it to finish, or cancel it, and try again.


Frequently asked questions

The schedule does not run at the time I want

Check timezone. If you omit it you get UTC. Writing only cron: "0 0 9 * * ?" runs at 6 PM Korea time.

trigger:
  kind: SCHEDULER
  cron: "0 0 9 * * ?"
  timezone: "Asia/Seoul"     # ← required

Check that the cron has six fields too. The first one is seconds. → Details

I called the webhook, got a 200, and nothing happened

200 means "received, thanks", and the workflow runs asynchronously in the background. Check the real result in the execution history. Nine times out of ten there is a FAILED sitting there.

A field I sent to the webhook never reaches the next node

The trigger's input-schema is a whitelist. Fields not listed in properties are dropped silently. Add every field you want to use to properties.

I want to pause a schedule for a while

Do not delete the workflow — turn it off. The toggle on the list and detail screens switches it, and the cron stops firing while it is off. → 10. Executions and Monitoring

An execution failed and nobody noticed

Configure the failure alert webhook on the Notifications screen. → 10. Executions and Monitoring

I'm in the middle of editing a workflow and it won't save

The graph structure may not line up yet. The error message tells you what is wrong. Expressions are not checked at save time, so an expression will never be what blocks a save.

The workflow the AI built fails when it runs

validate_workflow checks the graph structure only. A wrong ${...} path only shows up when it runs. Tell the AI to "run it and fix it if it fails" and it will iterate on its own.

If I move to another workspace, do my settings come with me?

No. Connections, variables and datasets are per workspace. You have to register them again in the new workspace.

What does it cost?

For the terms during the beta, see app.eeumsae.com and the terms of service. AI call costs are separate — eeumsae only makes the call on your behalf with your API key, and the bill comes from OpenAI, Anthropic and the rest directly.

What happens if I edit a workflow while it is running?

The shape at the moment the execution started is saved, so an execution already running is unaffected. Your edits apply from the next execution onward.


If it still does not work

Get in touch at contact@eeumsae.com. Sending the following along makes it much faster.

  • The workflow name or slug
  • The time of the failed execution
  • The verbatim error message from the execution history
  • (If you can) the workflow YAML — with API keys and tokens removed

Back to → Contents