Troubleshooting
Look up the code or message you see on this page. Each entry names the cause and what to run next. The Error codes page lists the codes by area.
Before you change anything, save the complete output of the failing command and reduce the problem to the smallest case that still fails. In the starter, start with the check that covers the whole machine:
npm run workshop:verifyIt stops at the first problem and prints its code as
workshop: IFLOW_…: <message>, often followed by a hint: line. Fix that one
item and run it again. When every check passes, it ends with
workshop:verify passed. The setup scripts run the same check, print PASS
or FAIL, and keep the full output in .runtime/setup-verify.log.
Do not edit or delete events to make a run pass: the event history is the record every later run replays. Do not print secrets to inspect them.
The starter’s commands print codes that start with IFLOW_. The complete list
is under Starter on the Error codes page.
IFLOW_NODE_VERSION_MISMATCH means the node in your shell is not exactly
26.8.1. Check it:
node --versionIt must print v26.8.1. The setup scripts do not install Node.js. Install
26.8.1 from nodejs.org. On macOS, the installer puts it in /usr/local/bin;
select it in the current Terminal and run the setup again:
export PATH=/usr/local/bin:$PATHThe starter installs its packages with npm ci from its package-lock.json.
IFLOW_DEPENDENCIES_MISSINGmeansnpm cihas not run, or did not finish. Runnpm ciin the project directory.IFLOW_PACKAGE_VERSION_MISMATCHmeans an@identity-flow/*package is installed at a version other than0.3.1. Runnpm ciagain; it installs exactly the versions in the lockfile.- If
npm cicannot download a package or reports an integrity error, keep its complete output (the setup script writes it to.runtime/setup-install.log) and write to contact@kenoxa.de. Do not install a different version instead.
Program and Workflow Test distribution in bin/
Section titled “Program and Workflow Test distribution in bin/”The starter expects the IdentityFlow program and the Workflow Test
distribution of the same release in bin/.
| Code | Cause | What to do |
|---|---|---|
IFLOW_DISTRIBUTION_MISSING | The program or the Workflow Test distribution is not in bin/. | Put both downloads next to the project or in ~/Downloads and run the setup script again. |
IFLOW_DISTRIBUTION_VERSION_MISMATCH | One of them does not report version 0.3.1. | Replace it with the 0.3.1 file for your platform. |
IFLOW_COHORT_SPLIT | The two were built from different source commits. | Use the program and the Workflow Test distribution from the same delivery. |
IFLOW_PROGRAM_UNUSABLE | One of them did not answer --version --json. | On macOS, see macOS stops the program. Otherwise download it again. |
If IFLOW_DISTRIBUTION_MISSING remains after setup, send the setup output and
.runtime/setup-install.log to contact@kenoxa.de.
The Workflow Test distribution is a folder whose files stay together; the
identity-flow-test executable does not start without the other files in it.
On Linux it needs glibc, so Alpine and other musl-based systems cannot run it.
-
IFLOW_CONTAINER_RUNTIME_UNAVAILABLEmeans no Docker server answered, or Docker Compose v2 is missing. Start Docker Desktop, OrbStack or the Docker Engine and run the command again. In WSL2, Docker Desktop must use its WSL2 backend with WSL integration turned on for your distribution. -
IFLOW_FIXTURES_NOT_RUNNINGmeans the starter’s local services, PostgreSQL and the sign-in server, are not up. Start them:Terminal window npm run workshop:start -- --background -
IFLOW_IMAGE_MISSINGmeans a container image the starter needs is not on this machine.workshop:verifydoes not download images;npm run workshop:startdoes. Run it with network access, or load the image from an archive withdocker load -i <archive>, then run the check again. -
IFLOW_POSTGRES_VERSION_MISMATCHmeans the starter’s PostgreSQL container reported a version other than 18.6, or did not answer at all. Read its log in the project directory:Terminal window docker compose --env-file .runtime/workshop.env logs postgres
Workflow Tests start their own PostgreSQL container, so Docker must be running for them too. Without Docker, point them at a PostgreSQL server you run yourself; see Use your own PostgreSQL.
The starter’s sign-in server serves HTTPS only, with a certificate from
mkcert. IFLOW_LOCAL_TRUST_MISSING means mkcert is missing, or its
local root certificate was never installed. Install mkcert, then run once:
mkcert -installOn Debian or Ubuntu, install mkcert with the NSS tools, so Linux browsers trust the same root:
sudo apt-get install mkcert libnss3-toolsmkcert -installnpm run workshop:start passes the mkcert root to the program itself. When
you start the program, or another Node.js command, by hand against the
starter’s sign-in server, set NODE_EXTRA_CA_CERTS first:
export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem"The same variable takes your company’s root certificate when your OIDC provider or a TLS-intercepting proxy uses a certificate from a private authority; see Provider certificate not trusted. Do not turn certificate checks off instead.
In WSL2 the browser runs on Windows and does not trust the Linux root. Install the mkcert root in Windows as described in mkcert’s instructions for other systems.
| Service | Default port | Override |
|---|---|---|
| program | 4173 | WORKSHOP_PROGRAM_PORT |
| PostgreSQL | 15544 | WORKSHOP_POSTGRES_PORT |
| sign-in server | 5566 | WORKSHOP_OIDC_PORT |
IFLOW_PORT_IN_USE means another process already listens on the program port.
Find it:
lsof -nP -iTCP:4173 -sTCP:LISTENStop that process, or start on a free port. The starter rewrites the addresses that depend on the port:
WORKSHOP_PROGRAM_PORT=4180 npm run workshop:startA program or Workflow Test distribution downloaded with a browser is
quarantined. macOS stops the unsigned executable at its first start with exit
code 137; the program itself prints nothing, and zsh reports killed. The
starter’s setup-macos.sh offers to remove the quarantine from bin/; run it
again and confirm. For a file outside the starter, start it once, then approve
it in System Settings → Privacy & Security → Open Anyway. The approval stays
with that file. The Workflow Test distribution contains more than one
executable; approve each one macOS blocks. Approve only files
from your IdentityFlow delivery, and do not turn Gatekeeper off.
The program runs its startup steps before it listens on its port. It stops at the first failure and writes the reason at the end of its log.
In the starter, IFLOW_PROGRAM_EXITED
means the program stopped during startup. The starter keeps the program’s log
in .runtime/program.log; read its end:
tail -n 50 .runtime/program.lognpm run workshop:logs shows the log only while the program runs.
The engine’s codes start with WF_; see
Engine and program.
The IdentityFlow program can write a report.*.json diagnostic report in its
working directory after a fatal Node.js error, such as running out of memory;
reports from version 0.3.0 and earlier also contain environment variables, so
check any such reports you have shared and rotate the credentials they contain.
The message names the key. The most common ones:
| Message | What to do |
|---|---|
Parsing config failed (<file>, line <n>, column <n>): invalid <YAML, TOML or JSON> syntax | Fix the syntax at that line and column. an included configuration file means a file your configuration includes or requires. A JSON error can come without a position; then check the whole file. |
Loading configuration failed (line <n>, column <n>): the configuration could not be parsed or resolved | Check the configuration file’s syntax, its ${…} substitutions, its includes and NODE_CONFIG_STRICT, starting at that line and column if the message shows them. |
auth.oidc.issuer must use HTTPS outside a loopback deployment | Use an https:// issuer. Plain HTTP works only with NODE_ENV development or workshop and the literal address 127.0.0.1 or [::1], never localhost. |
auth.oidc.redirectUri must use HTTPS outside a loopback deployment | The same rule for the redirect URI. |
identity.originProviders must contain auth.oidc.origin "<origin>" | Add the origin to identity.originProviders; see Origin and provider mismatch. |
auth.oidc.authorizationTtl must be at most 10 minutes | Lower the value. |
auth.oidc.sessionTtl must be at most 8 hours | Lower the value. |
auth.oidc.scopes must include openid | Add openid to scopes. |
Expected exactly one authorization module, discovered <n> | Make authorization.include match exactly one authorization.ts. |
Access Configuration Candidate <digest> does not match the reviewed digest <reviewed>; … | authorization.ts changed since it was reviewed. Review it, then set authorization.activate.digest to the new digest. |
Every key and its limits are in the configuration reference.
WF_DATABASE_MIGRATION_MISMATCH with
Database was migrated by a newer or incompatible IdentityFlow program, or its migration history has a gap.
means the database records a migration this program does not know. A program
never migrates a database back. Start the program version that migrated it, or
restore a backup taken before the upgrade; see
Database migrations.
A 0.2.0 program started against a database that 0.3.0 has migrated fails
instead with
42723: function "uuid_generate_v7" already exists with same argument types.
In the starter, the database holds only practice data. This command deletes it, and the next start creates a new one:
npm run workshop:stop -- --volumesIFLOW_DATABASE_CREDENTIAL_MISMATCH means the kept database was created with
a different password than the one in .runtime/workshop.env. Restore the
earlier .runtime/workshop.env if you still have it; otherwise the reset above
fixes it by deleting the practice database.
WF_DEFINITION_BUNDLE_CHANGED with
Workflow Definition "<name>" version "<version>" has a different bundle. … Raise the version before starting.
means a file changed while its name and version stayed the same. A
deployed version cannot change. Raise the version of the named definition and
start again; see
Versions and changed bundles.
The bundle also contains the installed packages. Installing the same project with a different package manager, or after a package upgrade, can change it even when your code did not.
The program fetches your OIDC provider’s discovery document at startup. If
the provider’s certificate comes from an authority Node.js does not trust, the
start stops there. Put that authority’s root certificate in a PEM file and
start the program with NODE_EXTRA_CA_CERTS set to that file. The variable
takes one file; to trust several roots, such as the mkcert root and your
company’s, put all of them into that one file.
After the provider sends the browser back, a failed sign-in shows
Unable to complete sign-in (<reason>): <message>. The reason tells you what
went wrong:
| Reason | Cause and what to do |
|---|---|
transaction_missing | The browser holds no sign-in for this callback: it was started under another address, expired, or already completed. Open IdentityFlow under the address in auth.oidc.redirectUri and sign in again. |
state_mismatch | The callback does not belong to the sign-in this browser started. Sign in again. |
transaction_expired | The sign-in took longer than auth.oidc.authorizationTtl, or was already used. Sign in again. |
token_exchange_failed | The provider did not confirm the sign-in. Check issuer, clientId and clientSecret, and that the provider has redirectUri registered exactly. |
Every sign-in carries the origin from auth.oidc.origin, and
identity.originProviders maps that origin to the provider ID your hooks file
registers. Principals match only within one provider: role:approver from
provider acme and role:approver from provider hr are different
principals.
- At startup,
identity.originProviders must contain auth.oidc.origin "<origin>"means the origin has no entry, andOrigin "<origin>" routes to missing provider "<provider>"means no loaded hooks file registers that provider ID. - An origin mapped to the wrong provider starts without an error. The account then sees no dialogs and no workflows, because none of its principals come from the provider the assignees and access entries name.
- In the starter,
IFLOW_ORIGIN_MISMATCHandIFLOW_PROVIDER_ID_MISMATCHmean the configuration no longer routes the starter’s sign-in toacme.
See Route the login to your provider.
A person may answer a dialog only when their account holds one of its assignee principals at the moment they submit. The dialog then appears under Assigned to me; otherwise it does not, and a submitted answer is refused.
- Sign in as that person and open My access (
/access). It lists the principals IdentityFlow last read from the provider for the account. - Compare them with the dialog’s assignees, provider ID first, then subject.
- If the list is wrong, the cause is in your hooks file or your directory, not in the workflow. IdentityFlow reads the principals again for every command, so a fix takes effect on the next answer.
An operator can also give the dialog to other principals; see Reassign a pending dialog.
When the workflow catalog is empty for everyone, either no Workflow Definition
was deployed or no access configuration is active. The program deploys only
the default export of each workflow file, one workflow per file; a file
without a valid default export is logged as workflow bundle invalid and
skipped. A definition without draft: false is skipped with the log line
Skipping deployment of draft workflow:. See
Which files are loaded. Without an active access
configuration, the log shows
Access Configuration Candidate <digest> compiled and left inert, and in the
starter npm run workshop:start stops with IFLOW_ACCESS_NOT_ACTIVE. Add an
activate block to the authorization configuration; see
Activate the configuration at startup.
When only some accounts see nothing, compare their principals on My access
with the entries in authorization.ts.
A change event from your directory that IdentityFlow does not accept gets an
HTTP status that names the reason, such as 401, 403 or 409. See
What IdentityFlow checks
and Webhooks on the Error codes page.
Read the code of the WorkflowTestError first. The message names the
workflow, the step, the acting account and the events so far, and leaves out
parameters, answers and secrets, so you can share it as it is. The codes are
listed under Workflow Tests.
vitest run prints No test files found, then
The Workflow Test runtime is not included in the public @identity-flow/testing package.
and exits with code 1. The files were found; the setup file stopped the run.
Workflow Tests run only with the Workflow Test distribution. In the starter:
npm run test:workflowIn your own project, run its identity-flow-test --run from the project
directory; see Run. Hook tests with
createHookTestHost() do run under plain Vitest, with a Vitest configuration
that does not load workflow-test.setup.ts.
A Workflow Test file must end in .case.ts. Vitest skips other names without
a warning; in the starter, IFLOW_NO_TESTS_SELECTED reports an include
pattern that matches no file.
WF_TEST_BINDING_FIXTURE_MISSING means the workflow used a
binding that the test did not
replace. Register a fixture with fixture(Binding, value) before start().
The test never falls back to the real binding. The complete message is shown
under Diagnostic contract.
WF_TEST_WAIT_TIMEOUT means flow.waitFor did not see the expected state in
time. It waits 4,000 milliseconds by default. Check the step the message names
first: a dialog that the test never answers also ends in a timeout.
- A
flow.sleepor a retry delay runs in real time. Pass a largertimeout, such asflow.waitFor(instance, { timeout: 30_000 }), and setretriesexplicitly on steps whose fixture throws; the default is five attempts one minute apart. - Keep Vitest’s
testTimeout, 5 seconds by default, above your longest wait.
See Wait for later steps.
WF_TEST_MUTATION_REJECTED: the account is not an assignee of the dialog, or the start parameters are invalid. See Test who may act.WF_TEST_UNSUPPORTED_CALL: the workflow, or one of its children, reachedflow.request, which Workflow Tests do not support in 0.3.1, orflow.startcould not create a child workflow. The message names the API and the step.WF_TEST_CHILD_DEFINITION_MISMATCH:toHaveChildreceived a definition that is not registered or does not match the child.WF_TEST_INSTANCE_ERRORED: the instance ended asERROREDwhile the test waited, for example after an uncaught error or an answer that failed the dialog’s schema.
When a request reaches GraphQL execution, IdentityFlow answers with HTTP 200
even if it fails; the error is in
errors[].extensions.code. All codes are listed under
GraphQL API.
Authentication required means the request carried no valid
identity_flow_session cookie: the person never signed in, or the session
passed auth.oidc.sessionTtl, at most 8 hours. Send the browser to
/auth/login?returnTo=<your path>. 0.3.1 has no token for clients without a
browser session; see
Where your UI must run.
Unexpected error. with INTERNAL_SERVER_ERROR means a server error. The
program’s log at the same moment names it. A refused command does not cause
this message: it returns its own code, such as NOT_FOUND or CONFLICT; see
Errors.
An instance that failed with an Error, such as most ERRORED instances or
one terminated because it passed its until deadline, returns businessData: null, as does an active instance that was never paused. A failure recorded
as plain data, such as a thrown object, still shows that data. That is not an error;
the instance page in the IdentityFlow UI shows its steps.
Lists have no total or facets; a query that selects them fails with
GRAPHQL_VALIDATION_FAILED. Remove them. To read more than one page, select
pageInfo { hasNextPage endCursor } and pass endCursor as after; a
malformed cursor returns BAD_USER_INPUT Invalid pagination cursor. See
List arguments.
GRAPHQL_VALIDATION_FAILED means the query does not match the schema. The
program also rejects introspection this way, so tools that load the schema
from the server fail; use the schema from the
GraphQL API reference instead.
If none of this helps, collect what What to record when you report a problem lists and write to contact@kenoxa.de.