Error codes
Find the code you see in a log line, a test failure or a response, read what it means, and apply the fix in the last column. Each section covers one source. For symptoms without a code, see Troubleshooting. Terms such as instance, step and access function are explained in Concepts.
The IdentityFlow program prints these codes in its log. Both stop the start, and the program exits.
| Code | Meaning | What to do |
|---|---|---|
WF_DEFINITION_BUNDLE_CHANGED | A Workflow Definition changed, but its name and version are already deployed with a different bundle. The message names the definition, the version and both hashes, and ends with Raise the version before starting. | Raise version of the named definition, then start again. See Versions and changed bundles. |
WF_DATABASE_MIGRATION_MISMATCH | Database was migrated by a newer or incompatible IdentityFlow program, or its migration history has a gap. The message names the recorded migration key and the newest key this program knows. | Start the program version that migrated the database, usually the newer one, or restore a backup taken before the upgrade. See Database migrations. |
The codes below come from the error classes in @identity-flow/sdk, and your
workflow code can throw them too; see
Errors you throw or handle.
WF_NON_RETRYABLE, WF_VALIDATION, WF_TIMEOUT and WF_ASSERTION are
recorded on a failed step or instance. The other codes refuse a command, such as
starting a workflow, answering a dialog or operating an instance. In 0.3.0 you
see them as the cause of WF_TEST_MUTATION_REJECTED in a Workflow Test, or when
your workflow code throws them.
| Code | Meaning | What to do |
|---|---|---|
WF_NON_RETRYABLE | The step threw a NonRetryableError: a permanent failure, so no retry follows. | Fix the cause the message names. Catch the error in the workflow if the failure is a business outcome. |
WF_VALIDATION | A value failed its schema: start parameters, a step result, or a dialog answer checked when the workflow continued. Not retried. | Read the issues in the error. For dialog answers, validate in your UI before calling completeDialog; see Dialogs. |
WF_TIMEOUT | A dialog, request, child workflow or instance passed its until deadline. Not retried. | Set a later until, or catch the error in the workflow and handle the missed deadline. |
WF_ASSERTION | A flow.assert(condition, message) call got a falsy condition. Not retried. | Fix the input or the state the assertion checks. |
WF_AUTHORIZATION_DENIED | The engine could not confirm the acting account’s authority, for example because the provider did not return current principals for a command. | Check that the identity provider behind the account’s origin answers. See Connect your identity provider. |
AUTHORIZATION_PRINCIPAL_LIMIT_EXCEEDED | A provider returned more principals for one account than the engine’s hard ceiling, 7,000 by default. The account’s reads and commands fail. | Reduce the principals your provider returns for that account, for example by returning roles instead of individual memberships. |
WF_NOT_FOUND | The resource does not exist, or the acting account may not discover it. Both cases look the same by design. | Check the ID and the account’s access functions. |
WF_FORBIDDEN | The account may see the resource but may not perform the action. | Grant the access function the action needs, such as operator; see Access control. |
WF_CONFLICT | The action is allowed, but the resource is no longer in the required state, for example Workflow dialog is no longer pending. | Read the resource again and decide on its current state. |
WF_LOCKED | Another command or engine holds the lock on the resource, for example Workflow Resource is temporarily locked. | Retry the command after a short wait. |
The GraphQL API does not pass the refusal codes on in 0.3.0. A refused command
arrives as INTERNAL_SERVER_ERROR; see GraphQL API below.
Every failure of the Workflow Test driver is a WorkflowTestError with one of
these codes. The full behavior is in Testing API.
| Code | Meaning | What to do |
|---|---|---|
WF_TEST_WAIT_TIMEOUT | flow.waitFor did not see the expected state within its timeout. | Check the step the message names. If the workflow sleeps or retries, raise timeout; see Wait options. |
WF_TEST_MUTATION_REJECTED | start or completeActivity was refused: the account is not an assignee, or the start parameters are invalid. | Act as an account whose principals match the dialog’s assignees, or fix the parameters. If the refusal is the expected behavior, assert on this code. |
WF_TEST_BINDING_FIXTURE_MISSING | The workflow used a binding that has no fixture in this test. | Register it with fixture(binding, value) before start(). |
WF_TEST_UNSUPPORTED_CALL | The workflow or one of its children reached flow.request, or flow.start could not create a child. | Workflow Tests do not run request steps. For a child, register its definition in workflows with the version the parent asks for. |
WF_TEST_CHILD_DEFINITION_MISMATCH | toHaveChild received a definition that is not registered or is not the child the step started. | Pass the child’s own definition, and register it in workflows. |
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 schema. | Read the error in the message. If the failure is the expected behavior, assert on this code. |
Without the Workflow Test distribution, workflowTest throws
The Workflow Test runtime is not included in the public @identity-flow/testing package.
without a code. Run the tests with identity-flow-test --run from the
distribution; see Test workflows.
The GraphQL API returns HTTP 200 for every request that reaches GraphQL
execution, errors included. Each error sits in errors[], with its code in
extensions.code. Invalid JSON in the request body returns HTTP 400. See
GraphQL API for the operations.
extensions.code | Meaning | What to do |
|---|---|---|
UNAUTHENTICATED | Authentication required: the request carries no valid session cookie. | Sign in through /auth/login and send the identity_flow_session cookie; see Build your own UI. |
NOT_FOUND | Resource not found: the resource does not exist, or the signed-in account may not see it. The two cases are not distinguishable. | Check the ID and the account’s access. Do not show the two cases differently in your UI. |
BAD_USER_INPUT | An argument is malformed: first must be between 1 and 100, Invalid pagination cursor, Invalid <name> filter, or Invalid <field> for an ID that is not a valid IdentityFlow ID. | Fix the argument the message names. |
INTERNAL_SERVER_ERROR | Unexpected error. In 0.3.0 this includes every refused command: the account is not an assignee or lacks the access function, the ID is unknown, or the start parameters are invalid. | Check the account’s assignment and access, the ID and the parameters. Read the resource again to see its state. |
GRAPHQL_VALIDATION_FAILED | The query does not match the schema, for example an unknown field. Introspection queries also fail with this code, because the program disables introspection outside development. | Compare the query with the operations in GraphQL API. |
GRAPHQL_PARSE_FAILED | The query is not valid GraphQL syntax, or it has more than 1,000 tokens. | Fix the syntax, or split the query. |
The API also refuses queries nested deeper than 20 levels, with more than 15 aliases, or with more than 50 directives. In 0.3.0 the alias and directive errors carry no code.
The change-event endpoint POST /-hooks/<hook>/<webhook> answers with an HTTP
status and a JSON body { "error": "<value>" }. Causes, limits and the order of
checks are in Webhook protocol.
| Status | error | What to do |
|---|---|---|
| 400 | invalid_request_body | Send JSON that matches the webhook’s body schema and maps to at least one valid envelope for a provider of that hooks file. |
| 401 | authentication_required | Send the signature and timestamp headers the webhook definition names. |
| 403 | authentication_failed | Sign the exact raw body with the shared secret and the current time; check the sender’s clock against maxClockSkew. |
| 404 | webhook_not_found | Check the hook name from defineHooks and the webhook name from http.webhook in the URL. |
| 409 | change_event_conflict | Send a new eventId for changed content. The same source and eventId may only be resent with identical content. |
| 413 | request_too_large | Split the request so it stays below the body and envelope limits. |
| 429 | rate_limit_exceeded | Wait the seconds in Retry-After, then resend. |
| 503 | change_ingress_unavailable | Resend later. If it persists, check that secret, the schema and map finish within 5 seconds. |
The starter’s scripts print one code per failure on standard error, as
workshop: <diagnostic code>: <message>, often followed by workshop: hint: <what to do>,
and exit with status 1. The tables follow the scripts in the starter’s
package.json. For the setup, see Tutorial: set up the starter.
Printed by npm run workshop:verify, and by npm run workshop:start before it
starts anything. IFLOW_DISTRIBUTION_MISSING and
IFLOW_DISTRIBUTION_VERSION_MISMATCH also come from npm run test:workflow and
npm run exercise.
| Code | Meaning | What to do |
|---|---|---|
IFLOW_NODE_VERSION_MISMATCH | Node.js is not exactly the version the starter requires, 26.8.1. | Install Node.js 26.8.1 and run again. |
IFLOW_CONTAINER_RUNTIME_UNAVAILABLE | No Docker server answered, or Docker Compose v2 is missing. | Start Docker Desktop or another Compose v2 runtime. |
IFLOW_LOCAL_TRUST_MISSING | mkcert is not installed, or mkcert -install never ran. | Install mkcert and run mkcert -install once. |
IFLOW_IMAGES_LOCK_MISSING | images.lock.json is not in the project. | Extract the starter archive again. |
IFLOW_IMAGES_LOCK_INVALID | images.lock.json is unreadable, records no image, or lacks a platform. | Extract the starter archive again. |
IFLOW_IMAGE_MISSING | A container image the starter needs is not present and could not be pulled. | Run npm run workshop:start with network access, or load the image with docker load -i <archive>. |
IFLOW_IMAGE_MISMATCH | A local image is not the one images.lock.json records. | Remove the local image, then pull or load the recorded one. |
IFLOW_PROJECT_INCOMPLETE | A required project path is missing. | Extract the starter archive again. |
IFLOW_DEPENDENCIES_MISSING | A required npm package is not installed. | Run npm ci. |
IFLOW_PACKAGE_VERSION_MISMATCH | An installed @identity-flow/* package is not version 0.3.0. | Run npm ci with the starter’s package-lock.json. |
IFLOW_CONFIG_SECRET_LITERAL | The configuration contains a literal clientSecret or password. | Replace the value with an ${ENVIRONMENT_VARIABLE} reference. |
IFLOW_ORIGIN_MISMATCH | auth.oidc.origin differs from the origin in fixtures/oidc/workshop-oidc.ts. | Set both to the same value. |
IFLOW_PROVIDER_ID_MISMATCH | identity.originProviders no longer routes the origin to acme. | Restore the acme entry for the origin. |
IFLOW_TEST_SELECTION_UNREADABLE | vitest.config.ts declares no tests/ include pattern. | Restore the include pattern for tests/. |
IFLOW_NO_TESTS_SELECTED | A Vitest include pattern selects no file, so a test run would pass without running anything. | Fix the pattern, or add the missing test files. |
IFLOW_FIXTURES_NOT_RUNNING | A fixture service of the project is not up or not healthy. | Run npm run workshop:start; if the code persists, inspect docker compose logs. |
IFLOW_POSTGRES_VERSION_MISMATCH | The running PostgreSQL is not exactly 18.6. | Use the PostgreSQL image from images.lock.json. |
IFLOW_DISTRIBUTION_MISSING | bin/identity-flow or bin/identity-flow-test is missing. | Place the 0.3.0 IdentityFlow program and Workflow Test distribution in bin/. |
IFLOW_DISTRIBUTION_VERSION_MISMATCH | A program in bin/ does not report version 0.3.0. | Replace it with the 0.3.0 release. |
IFLOW_DISTRIBUTION_UNIDENTIFIED | A program in bin/ reported no 40-character source commit. | Replace it with the program from the release. |
IFLOW_PROGRAM_UNUSABLE | A program in bin/ did not answer --version --json, or its answer was unreadable. | Install the program from the release again. |
IFLOW_COHORT_SPLIT | The program and the Workflow Test distribution were built from different source commits. | Install both from the same release. |
Printed by npm run workshop:start and npm run workshop:stop:
| Code | Meaning | What to do |
|---|---|---|
IFLOW_PORT_IN_USE | Another process already listens on the program port, 4173 by default. | Stop that process, or set the variable the message names to a free port and start again. |
IFLOW_PREFLIGHT_FAILED | workshop:verify rejected the machine before the start, or the started services afterwards. | Run npm run workshop:verify and fix the code it prints. |
IFLOW_WORKSHOP_ENV_STALE | .runtime/workshop.env was written by an older starter. | Run npm run workshop:stop, then npm run workshop:start. |
IFLOW_FIXTURES_INCOMPLETE | A fixture source file the start needs is missing. | Extract the starter archive again. |
IFLOW_DATABASE_CREDENTIAL_MISMATCH | The retained database volume was created with a different password. | Restore .runtime/workshop.env, or discard the database with npm run workshop:stop -- --volumes and start again. |
WF_DEFINITION_BUNDLE_CHANGED | A deployed Workflow Definition changed under the same version. | Raise the version of the named definition. |
IFLOW_PROGRAM_START_FAILED | The program could not be launched or kept running. | Read .runtime/program.log. |
IFLOW_PROGRAM_EXITED | The program exited during startup. | Read .runtime/program.log for the startup error. If it shows WF_DATABASE_MIGRATION_MISMATCH, start the newer program or reset the starter database with npm run workshop:stop -- --volumes; see Engine and program. |
IFLOW_READINESS_TIMEOUT | A service, the program or the Workflow Definition inventory did not become ready in time. | Read .runtime/program.log and docker compose logs. |
IFLOW_ACCESS_NOT_ACTIVE | No Access Configuration is active, so all configurable access is denied. | Check the authorization.activate block in config/identity-flow.workshop.conf; see Access control. |
IFLOW_DEFINITION_NOT_REDEPLOYED | The program kept the stored bundle of a changed definition instead of stopping. Only a 0.2.0 program does this. | Raise the version of the named definition, or reset the starter database with npm run workshop:stop -- --volumes. |
IFLOW_BUNDLE_HASH_UNAVAILABLE | The stored bundle hashes could not be read from the database. | Check that the PostgreSQL service runs, then start again. |
IFLOW_CLEANUP_FAILED | Stopping the program or the services after a run failed. | Run npm run workshop:stop. |
IFLOW_PROGRAM_STOP_TIMEOUT | The program did not exit within the grace period after SIGTERM. | Read .runtime/program.log before you stop the process by hand. |
IFLOW_FIXTURES_STOP_FAILED | docker compose stop failed. | Check Docker, then run npm run workshop:stop again. |
IFLOW_FIXTURES_RESET_FAILED | docker compose down --volumes failed during npm run workshop:stop -- --volumes. | Check Docker, then run the command again. |
Printed by npm run workshop:logs, npm run workshop:refresh and
npm run workshop:inventory:
| Code | Meaning | What to do |
|---|---|---|
IFLOW_WORKSHOP_NOT_STARTED | No program is running in this project. | Run npm run workshop:start first. |
IFLOW_LOG_UNAVAILABLE | The program log file is missing. | Start the program again with npm run workshop:start. |
IFLOW_LOG_OFFSET_INVALID | .runtime/program.log is shorter than the recorded start of this run. | Do not truncate or rotate the log while the program runs; restart the program. |
IFLOW_UNKNOWN_SCENARIO | workshop:refresh got a scenario name it does not know. | Use one of the names the hint lists. |
IFLOW_WEBHOOK_SECRET_MISSING | The recorded environment holds no webhook secret. | Run npm run workshop:stop, then npm run workshop:start. |
IFLOW_WEBHOOK_REJECTED | The program did not accept the change event; the message gives the HTTP status. | Look up the status under Webhooks. |
IFLOW_FIXTURE_CONTRACT_CHANGED | A fixture module no longer exports what the script needs. | Restore the export the message names. |
IFLOW_SOURCE_CHANGE_FAILED | Processing the change event failed permanently. | Open Failed work in the web application for the reason; see Operate running workflows. |
IFLOW_UNKNOWN_FIXTURE_ACCOUNT | --as names no account of the starter’s sign-in page. | Use one of the account names the hint lists. |
IFLOW_LOGIN_FAILED | The scripted sign-in did not complete. | Check with npm run workshop:status that the program and the sign-in service run. |
IFLOW_QUERY_FAILED | The GraphQL API refused or rejected the catalog query. | Read the message; look up a GraphQL code under GraphQL API. |
IFLOW_BUNDLE_HASH_MISSING | A stored Workflow Definition has no bundle hash. | Reset the starter database with npm run workshop:stop -- --volumes and start again. |
IFLOW_INVENTORY_AMBIGUOUS | A workflow name has more than one stored version, so the inventory cannot join on names. | Compare the versions by hand. |
IFLOW_ACCESS_NOT_ACTIVE | The GraphQL API returned no workflow although definitions are stored. | Activate an Access Configuration; see Access control. |
Printed by npm run exercise:
| Code | Meaning | What to do |
|---|---|---|
IFLOW_EXERCISE_ARGUMENT | An unknown option, or more than one practice task at a time. | Pass one practice task, and only the options the script knows. |
IFLOW_EXERCISE_REFERENCE | A practice task’s README is missing, or a task file names a wrong or missing task number. | Extract the starter archive again. |
IFLOW_EXERCISE_UNKNOWN | No practice task matches the selector. | Use the number of a directory under exercises/. |
IFLOW_EXERCISE_MISSING | There is no practice task directory under exercises/. | Extract the starter archive again. |
IFLOW_EXERCISE_TYPECHECK_UNAVAILABLE | typescript is not installed. | Run npm ci. |
IFLOW_EXERCISE_TYPE_ERROR | The practice task does not type-check, so its tests do not run. | Fix the type errors tsc prints. |
Codes that start with IFLOW_ACME_, such as IFLOW_ACME_UNKNOWN_EMPLOYEE, are
not script failures. The starter’s example integration and practice task bindings
throw them inside a running workflow, so a workflow can catch them by code.