Skip to content

Troubleshooting ​

Symptoms you are likely to hit, and what each one actually means.

A service is stuck on "starting" ​

A yellow starting state means Kranz is waiting for evidence, not that something is broken. Focus the service and press 2 to see what it waits for.

Waiting for a dependency. Details shows which one. The dependency's readiness must pass before this service starts. Check the dependency's own readiness probe — if the probe is wrong, the gate never opens.

Waiting for its own readiness. The process started, but the probe has not passed yet. Common causes:

  • the probe URL points at a port the service does not actually use;
  • the service binds localhost only, while the probe uses a different host;
  • initial_delay is shorter than the real startup time and the failures have not yet accumulated to failure_threshold.

To see whether the probe or the service is at fault, run the probe by hand:

bash
curl -v http://127.0.0.1:3001/ready

If that works while Kranz still waits, the probe configuration and the real endpoint disagree — compare them in Details.

A port is already taken ​

Kranz checks declared ports before starting and names the owner rather than failing obscurely. The dialog distinguishes a process Kranz manages from an external one, and terminating an external process always requires your explicit confirmation.

If the port belongs to a leftover process from a previous session, stop it from the dialog. If it belongs to something you want to keep, change the service's port or start the other tool instead.

A service shows "unknown" ​

unknown only applies to detached resources, and it means the status probe could not tell Kranz what the resource is doing. It is a deliberate "no evidence" state, not a failure.

Causes, in order of likelihood:

  1. The probe host is unreachable. An SSH probe against a sleeping laptop cannot answer. Kranz shows unknown instead of claiming stopped.

  2. The probe timed out. Raise timeout; a remote probe often needs more than the default 2s.

  3. The probe returned an unclassified exit code. This happens only if you declared stopped_exit_codes — a code in neither set is unclassified by design. Check the code your script actually returns:

    bash
    ssh host ./stack-status.sh; echo "exit: $?"

The service's log pane records the reason as [Kranz] Status unavailable: …. An unknown resource is polled on the slower stopped_interval, so recovery can take up to 30 seconds by default.

A service did not start and mentions a prerequisite ​

A before_start entry failed, so Kranz did not start the service against an unprepared environment. The logs name the action and what happened:

text
[Kranz] Prerequisite failed: action "migrate" · exited with code 1

Run that action on its own — expand the service with Enter, select the action, press s — and read its output. Prerequisites with run: once are remembered only after they succeed, so fixing the cause and starting again retries it.

Detached logs are empty ​

A detached resource has no process for Kranz to read output from. It shows logs only when you provide lifecycle.logs, and only while it is running:

yaml
lifecycle:
  logs:
    command: docker compose logs -f --tail=100

The command must stream and stay attached. A command that prints once and exits produces one burst of output and then nothing.

Mouse clicks stop working ​

Some integrated terminals silently reset mouse reporting when focus moves. Kranz re-enables tracking periodically and when the window regains focus, so clicking again usually recovers within a second. Keyboard control is never affected, and every mouse action has a key binding — see controls.

Colors look wrong or unreadable ​

Kranz derives its palette from the terminal background by default. If your terminal reports its background inaccurately, pin the mode explicitly:

yaml
ui:
  color_mode: dark        # or light
  background: theme       # stop deriving from the terminal

Ctrl+T opens the live picker to try values before saving them. See appearance.

Configuration changes have no effect ​

Kranz watches the selected configuration and referenced dotenv files. The TUI shows when they change; press Ctrl+L to apply a valid change. A CLI or MCP client can request a reload explicitly. Running services with changed settings keep their accepted snapshot until they are restarted.

  • The change was invalid. The previous configuration keeps running and the error is reported. Fix the error and save again.
  • The file is not one Kranz loaded. A conventional root file wins in its own directory; otherwise recursive discovery builds a virtual project. Run kranz config sources (or press m in the dashboard) to see every loaded file as an include tree. A missing branch is usually a glob that matched elsewhere, a discovery root or max_depth that is too narrow, or an include_depth_truncated diagnostic in kranz config check.
  • The value comes from an override layer or protected policy. Run kranz config sources --by-service to see which files overrode the service, then kranz config explain SERVICE for the ordered field provenance.
  • A partial file passed with -f adds services instead of changing them.-f composes complete projects; pass partial files with --override.
  • An override layer seems ignored. A file's own overrides: list patches only that file's services by their original names (api). To change a service another file contributes, pass --override and use its display name (catalog/api).

If a reload removes a running service, choose whether to stop it or keep it running outside the configured list. A service that cannot be stopped leaves the accepted configuration in place and produces an error.

An environment variable is not what I expect ​

Precedence runs from lowest to highest:

  1. .env beside the configuration file that declares the service
  2. defaults.env
  3. defaults.env_files, in order
  4. service env_files, in order
  5. service env

A variable already exported in your shell wins over the adjacent .env, but never over an explicit configuration value. Details shows the resolved environment file list for the selected service.

Leaving the TUI leaves something running ​

First check which exit action you chose. Detach closes only the TUI, so the complete runtime and all of its services remain available to CLI, MCP, and a later TUI. Confirmed shutdown ends the runtime, but detached resources default to stop_on_exit: false, so shared external infrastructure is not torn down merely because the runtime ended. The quit dialog lists both parts of this contract before you choose.

Set stop_on_exit: true if runtime shutdown should also run the external stop command. Process-supervised services always stop with their runtime; they cannot be left behind after shutdown.

A restart policy is being ignored ​

availability.restart applies to process-supervised services only. Kranz does not restart a detached resource it does not own — the configuration is rejected rather than silently ignored.

Also check max_restarts: once the limit is reached the service stays stopped until you start it again.

Still stuck ​

Open the lifecycle playground, which simulates managed, observe-only, healthy, unhealthy, and unknown resources locally with marker files. Reproducing a symptom there separates a Kranz problem from a configuration problem in your own project.

If it is a Kranz problem, please open an issue with your configuration and the version from kranz --version.

Released under the MIT License.