This documentation is available as Markdown. For the complete index, see llms.txt. Skip to content

Troubleshooting

For the complete documentation index, see llms.txt

Most refusals on a box are deliberate and say why. This page maps the message to the cause and to what to do.

Signing in

SymptomCause · what to do
This box has no free seats. Ask your administrator to free one or raise the licensed seat count.Every licensed seat is held by someone who signed in within the last 30 days. People already holding a seat still get in. An administrator disables someone on Administration → Users to free a seat, or you ask unotest to raise the count. The refusal is in the trail as seat.denied.
This account has been disabled on this box.An administrator disabled the account here. Administration → Users → enable.
Those credentials were not accepted.Break-glass username or password wrong, or the identity provider rejected the login (login.refused in the trail carries the provider’s reason).
That login attempt expired or was already used. Start again.The browser came back to a callback whose attempt has been used or timed out (a replayed link, a long pause at the provider). Start from https://<box>/.
redirect_uri_mismatch at the providerThe URI registered at your provider is not exactly https://<box>/_guard/login/callback.
Sign-in works, everyone is readonlyNo group mapping is in effect. For Google Workspace, part 2 (directory service account) is unfinished, or the mapping is empty.
none of this account’s groups are mapped to a roleThe person is in no mapped group — or in a parent group; nesting is not followed. Add the group they are directly in.
Everyone is refused right after setupUsually the impersonated administrator cannot read the directory, or a delegation scope is missing. The box refuses logins it cannot confirm.
Access outlives someone leavingGroups are read from the sign-in token rather than the directory, so nothing re-checks membership. Only a directory source can offboard.
429 too many login attempts10 attempts per minute per client address by default; wait for Retry-After. Behind your own proxy, every visitor may share one bucket — tell unotest the proxy’s address.

Identity provider unavailable

  • Open sessions keep working. A re-check that cannot reach the directory leaves the session alone and retries later; it never revokes on silence.
  • New logins are refused while the directory cannot answer — admitting a person nobody could vouch for is the one case where waiting is wrong.
  • Administrators use the break-glass account at https://<box>/_guard/login/static. It exists for exactly this day.
  • The box boots even if the provider is unreachable at start-up; discovery is retried, never cached as failed.

Pushing a bundle

MessageMeaning · what to do
this box runs @unotest/web X or newer; the bundle pins Y (min-version)The suite pins an older @unotest/web than the box supports. Bump it in unotest/package.json, commit the lockfile, push again.
this token is not valid for this box (unauthorized) — the CLI adds the token is unknown, revoked, or for another boxGet a new one from unotest (tokens are issued per project by the box’s operator).
… belongs to project "a" on this box, but the token is for "b" (scope-mismatch)The repository is mapped to another project than the token’s. Use that project’s token.
bundles on this box may not exceed N MB (too-large)Something got into unotest/ that should not travel (recordings, databases, downloads). Ignore it in git.
the upload did not arrive intact (malformed / id-mismatch)Retry. If it repeats, a proxy between you and the box is rewriting the body.
this token pushes bundles only (forbidden, on env push / env set)The token has the bundles scope. Values need a token minted with the values scope.
not pushed — N problem(s) above would fail on the box (exit 2)Refused on your machine; each line names the file and the fix. Nothing left it.
… answered 200 with something that is not a box's answerThe URL is not a box’s API — a login page, a proxy error. Check UNOTEST_BOX_URL; the box may also be older than this CLI.
--run needs --envName the box environment to run in.
no environment by that name on this box (unknown-environment)Environments are the operator’s decision; ask which exist.
the box no longer holds that bundle (unknown-bundle)It was collected under the retention policy. Push again.
name what to run with --collection <name>, or add a schedule (no-collections)Nothing was named and the environment’s schedules name nothing.
note: <env> has no value for NAMEThe suite declares a name that environment neither sets nor holds. Runs there stop at the first step that reads it — set it with env push <env> or env set <env> NAME.

An environment does not get its values

  • The viewer’s Variables panel shows nothing under box. The environment has no values yet: push them with npx @unotest/web env push <env> (a token with the values scope), or set them on Administration → Environments → the environment.
  • A value set on the box is not what a run sees. A secret wins over a variable of the same name, and a box-set value wins over the configuration. UNOTEST_* names are skipped by env push on purpose; set one with env set if you mean it.
  • A push removed something. env push replaces the layers: a name your files no longer carry is removed and listed. Put it back in the file, or use env set.
  • malformed from env push. The box has no values endpoint yet — it is older than the CLI. Ask unotest to update it.
  • The viewer reloaded and a debug session ended. Changing an environment’s values restarts its viewer, by design.

Environments page is empty

No environment is being served yet. The box has no bundle for that project. Push one; the viewer starts once there is something to show.

Schedules

  • A schedule did not run after a switch in the viewer. Schedules run the newest bundle of the environment’s defaultBranch, not the bundle someone selected. Push to the branch.
  • A missed night was not caught up. By design: the next run is the next one due.
  • A drift warning in the viewer. The schedule set the box computed differs from the one pushed — usually a config that reads process.env. Make the config compute the same set everywhere, or accept the box’s.
  • Cannot edit a schedule in the viewer. On a box schedules are read-only. Edit unotest/schedules.yaml or unotest.config, commit, push.
  • Nothing runs in a pr-<n> environment on its own. Preview environments never arm schedules; CI orders their runs.

Licence

SymptomMeaning
Banner License expired — N day(s) of grace left on the Environments pageThe licence has expired; the box keeps working for the grace period (14 days by default). Contact unotest to renew.
Page License required — The license has expired.Grace is over. The box answers every request outside sign-in with this page until a renewed licence is installed.
No license file found. / The license file is invalid.The licence file is missing or its signature does not verify. Contact unotest.
GET /_guard/health{"ok":true,"license":"grace"}The same states, for your monitoring: valid, grace, expired, missing, invalid.

What a box cannot reach

A run on the box executes inside the box’s container, on the box’s network. A scenario that passes on a laptop and fails on the box in its first step usually leans on something that exists only on the laptop:

  • localhost and port-forwards. kubectl port-forward, an SSH tunnel, a dev server on 127.0.0.1 — none of them exist on the box. Point preconditions and APP_BASE_URL at the environment’s public URL, and keep the health probe on that URL too.
  • Tools on the host. shell() runs inside the container: no kubectl, no gcloud, no project scripts outside the pushed suite. A scenario may call only files under unotest/ — the bundle is the whole file system it gets (the push refuses a scenario that imports from outside).
  • Secrets in shell(). .secrets values are not in a child process’s environment by default, on a box or locally; the scenario names the ones it exports through the sandbox.exportSecrets allowlist.
  • A judge service. UNOTEST_JUDGE_MODE=remote with a service on your machine does not work from the box; use local mode with @unotest/judge in the suite — see Judge on a box.
  • Your repository. The box never reads it: it runs the pushed bundle and nothing else — see Pushing suites.

GitHub checks

  • The check failed with “nothing was pushed for this commit”. The box waited 15 minutes for a bundle with that commit’s sha and none arrived. Make sure your CI job runs bundle push for every commit the App reports on.
  • A pull request from a fork is not run. By design — it would receive the environment’s secrets. A maintainer re-requests the check in GitHub to opt in.
  • A deployment did nothing. Its environment name is not mapped to a box environment; the box logs the missing name and drops the event.