Troubleshooting IO
Find out why a journey fails, hangs, shows the wrong value or can't be found, and fix it. Covers the common error messages, reloads, variables, vaults, API calls and Thales service nodes.
Start here
- 1
Note what the user saw
The exact message, the page, the time, and whether a reload was involved.
- 2
Check the flow is the one that runs
Is it Active? Is it the default for its flow type, or does the link carry its
flow_id? Is it the flow type you expect? - 3
Follow the path in the designer
Trace the run from the start node, output by output. Read where each output really goes, not where you expect it to go.
- 4
Look for unconnected outputs
Every output of every node needs a connection,
Failureand nested-flow outcomes included. - 5
Read the error
Log
{{flow.error.message}}on the failure path (see Find the error) and reproduce the problem.
Symptoms, causes and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| "Flow not found for current domain" right after you created the flow | New flows take about a minute to become reachable | Wait a minute and try again. |
"Flow not found for current domain" on a link with a # fragment | The fragment became part of flow_id | Put another parameter after flow_id: …&flow_id={flow-id}&src=app#…. |
| The flow URL doesn't start the flow | The flow is inactive | Activate it, or test it with a Debug link. |
| The flow isn't in the flow list | It is in another category, wasn't saved, or the page is stale | Check the category, save, and refresh the list. |
| The flow won't save | A required setting is empty, or a connection goes into a port the node doesn't have | Read the validation messages and fix each node they name. |
HTTP 500: "<output>" output of node <id> is not connected to any node | That output fired and had no connection. A script can also send an output it never declared. | Connect the output. For scripts, declare every output the code can send. |
HTTP 500: Start node not present in flow | The flow has no start node of a supported kind | Add the start node for the flow's type, as its first node. |
| A reload shows an error or restarts the journey | A reload resumes the session and the page takes its Failure output | Connect every page's Failure to a step that shows the page again. |
| The page after a reload has no styling (icon names show as words) | The theme is applied once per session and isn't sent again on resume | On reload paths, run the theme step again before showing the page. |
A page shows undefined or {{…}} where a value should be | The variable was stored with frontend availability off, was never set, or the template is misspelled | Turn frontend availability on for data a page shows (never for secrets), and check the variable name and path. |
| An old error, banner or value comes back | Setting a variable merges into its old value | Clear the variable with Delete Object before the step sets it again. |
| Sign-in always fails | Authenticate User reads other variable names than the form saved, or the password isn't saved | Use the form's variable name, such as {{login.username}} and {{login.password}}, and check the form saves both fields. |
| The page hangs after a button click | The page script returned without calling callback, or waited for DOMContentLoaded (which already fired) | Call callback on every path. Run page code directly, not in a load handler. |
| A button submits without the data your script adds | The button's ID equals the output key, so IO submits before your code finishes | Give the button a different ID (continue-btn for output continue) and call callback from your code. |
| A click reloads the page | Custom page HTML is rendered inside a form | Use type="button" on buttons and stop the default action. |
| The run fails right after Load From Vault | The vault name is wrong | Check the name under Flow Vaults → Vaults. The failure can't be routed, so fix the name. |
Invalid flow type from the API execute URL | The headless execute URL only runs flows of type webhook | Create the flow with type webhook. You can't change a flow's type afterwards. |
| The gateway rejects the execute URL | A trailing slash before ? | Remove the slash: …/io/flow/execute/api/webhook?domain_id=…. |
| An API flow returns the wrong HTTP status | The status is whatever the end node that ran says | Fix the status on that Flow - End Success Backend or Flow - End Failure Backend node. |
The browser response says success: true but the user sees a failure page | success means the call worked, not the journey | Judge the outcome by the page or end node that ran. |
| A nested flow's custom outcome goes nowhere | The outcome isn't declared on the caller | Add it to the caller's Variable Output Table with exactly the name of the library's Flow - Nested Custom End, and connect it. |
NoToken on a sign-in journey | Someone opened the flow URL directly instead of coming from the application | Expected. Show a page that sends the user back to the application. |
InvalidToken on a sign-in journey | The hand-over from Access expired or is invalid | Show a page that tells the user to start again from the application. |
| The imported flow is empty, or nodes are missing | The file was edited by hand and its structure is wrong | Export again from the source and import the unedited file. Compare node counts after every import. |
| You can't delete a flow | Active flows can't be deleted | Deactivate it first. If it is the default for its type, make another flow the default first, so the journey keeps working. |
| You can't delete a flow type | It was saved as not deletable, which is permanent | Rename it for reuse, for example as a sandbox type for test flows. |
When an HTTP request or service node fails
Backend - HTTP Request has only Success (2xx) and Failure. On Failure it still stores the response in its variable, but the shape depends on the response:
| Response | What `{{result.data}}` holds |
|---|---|
| 2xx with JSON | the parsed object |
| Error with a JSON body (for example 400 or 409) | the body, often as text: log {{result.data}} whole |
| Error with an empty body (often 401 or 403) | Internal error: Request failed with status code <N> |
{{flow.error.message}}holdsRequest failed with status code <N>. Log it together with{{result.data}}.- 401: the token is missing, expired, or not for this service. The client needs the service in its Default audiences. See Access clients and the API's Connect section.
- 403: the token lacks the operation's scope. Add it to the client's Default scopes (Scopes).
- The token request itself fails with HTTP 500: the client's scopes, joined with spaces, are longer than 1024 characters. Split them across clients.
- Each API page lists its own error codes, for example Identity Store: when a call fails.
Thales service nodes route known errors to their own outputs (such as NotFound, Conflict, BadRequest) and write details under their variable, for example {{ids.idsError.status}} and {{ids.idsError.message}}. 401 and 403 always go to Failure.
- `Failure` with an empty error variable usually means authentication or configuration, not data: an empty or wrong client secret (check its Load From Vault), a missing scope, or a missing audience.
- A result reads as `undefined`: read it through the node's variable,
{{ids.idsGetIdentityByAttributeResult.response.id}}. The bare{{idsGetIdentityByAttributeResult…}}never resolves. - Password Store, Action Challenge, TOTP and Recovery Codes nodes fail when no Identity Store lookup ran first. They need the user's identity ID and don't look the user up themselves.
- Use the output names your tenant's node shows in the designer. Many service nodes have no output called
Success.
Find the error
Add a Backend - Log node on the failure path, before the error page. It writes to the platform logs, never to the user:
{ "log": "[Sign-in] lookup FAILED | user={{login.username}} error={{flow.error.message}} response={{idsUser.data}}",
"log_level": "WARNING" }{{flow.error.message}}holds the error of the last node that failed.{{flow.error}}adds the stack.- Never log passwords, tokens, vault values or
{{flow}}. Log that a value is present, not the value. - The step-by-step trace of a run is logged at Debug level. On environments that keep only Info and above, you see what each node did, but not the path between them.
- One failed request can write the same error several times. Count requests, not log lines.
- Enable nodes tracking (flow settings) records every executed step in the platform. Turn it on for a flow you are investigating, and ask support for the records if you need them.
- Test an inactive copy with a Debug link while you investigate, so the live journey keeps running.
Remove temporary debug pages, Frontend - Log nodes and verbose logs before release. Browser logs are visible to every user, and large log lines slow every run.
Before you contact support
Collect these, so support can find the run quickly:
- The environment, the flow name and its flow ID (Copy ID in the flow list).
- The time of the failure, with time zone, and the flow session ID if you logged
{{flow.flow_session}}. - The node title and output where the run stopped, and the exact error message.
- What you already checked from this page.
Never send passwords, client secrets, tokens or vault values. Remove personal data from exports and screenshots before you share them.