Skip to content

Troubleshooting

Starter setup install and start Program startup configuration and DB Sign-in identity and access Workflow Tests runner and failures GraphQL clients queries and commands
Starter setup install and start Program startup configuration and DB Sign-in identity and access Workflow Tests runner and failures GraphQL clients queries and commands
Choose the area where the failure appears, then use its symptom or error code to find the next check.

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:

Terminal window
npm run workshop:verify

It 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:

Terminal window
node --version

It 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:

Terminal window
export PATH=/usr/local/bin:$PATH

The starter installs its packages with npm ci from its package-lock.json.

  • IFLOW_DEPENDENCIES_MISSING means npm ci has not run, or did not finish. Run npm ci in the project directory.
  • IFLOW_PACKAGE_VERSION_MISMATCH means an @identity-flow/* package is installed at a version other than 0.3.1. Run npm ci again; it installs exactly the versions in the lockfile.
  • If npm ci cannot 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.

The starter expects the IdentityFlow program and the Workflow Test distribution of the same release in bin/.

CodeCauseWhat to do
IFLOW_DISTRIBUTION_MISSINGThe 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_MISMATCHOne of them does not report version 0.3.1.Replace it with the 0.3.1 file for your platform.
IFLOW_COHORT_SPLITThe two were built from different source commits.Use the program and the Workflow Test distribution from the same delivery.
IFLOW_PROGRAM_UNUSABLEOne 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_UNAVAILABLE means 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_RUNNING means 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_MISSING means a container image the starter needs is not on this machine. workshop:verify does not download images; npm run workshop:start does. Run it with network access, or load the image from an archive with docker load -i <archive>, then run the check again.

  • IFLOW_POSTGRES_VERSION_MISMATCH means 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:

Terminal window
mkcert -install

On Debian or Ubuntu, install mkcert with the NSS tools, so Linux browsers trust the same root:

Terminal window
sudo apt-get install mkcert libnss3-tools
mkcert -install

npm 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:

Terminal window
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.

ServiceDefault portOverride
program4173WORKSHOP_PROGRAM_PORT
PostgreSQL15544WORKSHOP_POSTGRES_PORT
sign-in server5566WORKSHOP_OIDC_PORT

IFLOW_PORT_IN_USE means another process already listens on the program port. Find it:

Terminal window
lsof -nP -iTCP:4173 -sTCP:LISTEN

Stop that process, or start on a free port. The starter rewrites the addresses that depend on the port:

Terminal window
WORKSHOP_PROGRAM_PORT=4180 npm run workshop:start

A 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.

STARTUP STEPS Configuration read and check authorization.ts compile if set PostgreSQL connect, migrate Hooks, workflows load, deploy Activate access if activate set OIDC discovery fetch document Serve HTTP ready Start stops reason in log then then then then then then first failure
STARTUP STEPS Configuration read and check authorization.ts compile if set PostgreSQL connect, migrate Hooks, workflows load, deploy Activate access if activate set OIDC discovery fetch document Serve HTTP ready Start stops reason in log then then then then then then first failure
The program runs its startup steps in this order and stops at the first one that fails, with the reason in the log; it serves HTTP only after all of them succeeded.

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:

Terminal window
tail -n 50 .runtime/program.log

npm 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:

MessageWhat to do
Parsing config failed (<file>, line <n>, column <n>): invalid <YAML, TOML or JSON> syntaxFix 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 resolvedCheck 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 deploymentUse 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 deploymentThe 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 minutesLower the value.
auth.oidc.sessionTtl must be at most 8 hoursLower the value.
auth.oidc.scopes must include openidAdd 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:

Terminal window
npm run workshop:stop -- --volumes

IFLOW_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:

ReasonCause and what to do
transaction_missingThe 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_mismatchThe callback does not belong to the sign-in this browser started. Sign in again.
transaction_expiredThe sign-in took longer than auth.oidc.authorizationTtl, or was already used. Sign in again.
token_exchange_failedThe 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, and Origin "<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_MISMATCH and IFLOW_PROVIDER_ID_MISMATCH mean the configuration no longer routes the starter’s sign-in to acme.

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.

  1. Sign in as that person and open My access (/access). It lists the principals IdentityFlow last read from the provider for the account.
  2. Compare them with the dialog’s assignees, provider ID first, then subject.
  3. 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:

Terminal window
npm run test:workflow

In 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.sleep or a retry delay runs in real time. Pass a larger timeout, such as flow.waitFor(instance, { timeout: 30_000 }), and set retries explicitly 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, reached flow.request, which Workflow Tests do not support in 0.3.1, or flow.start could not create a child workflow. The message names the API and the step.
  • WF_TEST_CHILD_DEFINITION_MISMATCH: toHaveChild received a definition that is not registered or does not match the child.
  • WF_TEST_INSTANCE_ERRORED: the instance ended as ERRORED while 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.