Common problems
Each entry below starts from what a person sees, then gives the cause and the fix. Messages are quoted as gg and the control plane print them; text in angle brackets, such as <address>, stands for a value.
When a problem is not listed here, run gg doctor first. If it offers no fix, send a diagnostics bundle.
Not signed in
Section titled “Not signed in”What appears. A command stops with one of:
This machine is not signed in. Run gg login, then try again.The sign-in on this machine has expired or been revoked. Run gg login, then try again.Cause. Nobody has signed in on this machine, or the session has ended. A session ends when it expires, when it is revoked, or when the control plane no longer accepts it.
Fix. Run gg login and approve the sign-in in a browser, as described in Sign in. Then run gg whoami to check who the machine is signed in as.
On a runner installed as a service, sign in as the service’s user, for example sudo -u gg gg login on Linux, or enrol the machine with a token instead, as described in Add machines to the fleet.
The control plane cannot be reached
Section titled “The control plane cannot be reached”What appears.
Could not reach the control plane at <address>. Run gg doctor to check the connection.gg doctor then reports a failed control plane check. When no address has been set, its detail ends which is the built-in default because GG_CONTROL_PLANE is not set, and the address is http://localhost:5199.
Cause. Either gg has not been told where the organisation’s control plane is, or the address is right and the network or the control plane is not answering.
Fix. If the address is the built-in default, or is wrong, set it:
gg config set control-plane <address>An administrator can provide the address. If the address is right, check that this machine can reach it, for example from a browser. When gg config show lists GG_CONTROL_PLANE with the source environment, an environment variable is overriding the file, and the variable is the value to correct.
When the control plane answers with an error instead, the message is:
The control plane at <address> answered with an error (HTTP <code>). Run the command again; if this keeps happening, run gg bundle and send the result to the Good Grief team.A flight is refused because its repository is not registered
Section titled “A flight is refused because its repository is not registered”What appears. gg fly fails, nothing is created, and the control plane says:
'<repository>' is not a registered repository for this tenant. Registration is what makes a repository nameable at all - register it, POST /v1/airspace/repositories, and open the flight again.Cause. A flight may concern only a repository the organisation has registered. Registering gives the repository the name flights and rules use.
Fix. Register the repository with gg airspace repositories add, as described in Change the airspace: register a repository, then open the flight again. A new registration waits for approval at a gate before it can be used.
A flight is refused because of its repository or environment
Section titled “A flight is refused because of its repository or environment”What appears. gg fly fails, nothing is created, and the control plane says, for an environment:
This flight declares environment '<name>', and the composed envelope bounds flights to <names>. Declare one of those, or nothing - which inherits the bound when it names exactly one.The same message, with repository in place of environment, appears for a repository.
Cause. The organisation’s root rules list the environments and repositories flights may use, and this flight named one that is not on the list. See The envelope: environments:.
Fix. Open the flight again with one of the names the message lists, or with none when the list has only one entry. If the flight genuinely needs another environment or repository, add it to root’s list. Adding one loosens the rules, so it waits for approval. A new environment must also be charted first; see Change the airspace: chart an environment.
A flight stays in Ready and no machine takes it
Section titled “A flight stays in Ready and no machine takes it”What appears. The flight is open and has not been leased. gg show <flight> shows no runner.
Cause. When a flight is ready, its environment becomes a requirement on the machine that takes it. Only a runner whose labels include environment=<name> is offered the flight. If no running machine advertises that label, the flight waits. This is not an error, and nothing times out.
Fix.
-
Run
gg why <flight>andgg plan <flight>to see what the flight is waiting on. -
Run
gg runnersto see which runners are up, andgg runner labelsto see what each one advertises. -
Bring up a runner that advertises the environment. On a machine set up for it, set the label and start the runner:
Terminal window gg config set runner-labels environment=<name>gg runner upFor a machine enrolled under a fleet profile, the profile’s
environmentdecides this instead. For a pool of machines, a strategy provides the environment;gg strategieslists them, and with none it says:No strategy is in force. Nothing furnishes an environment, so a flight selecting one waits until a runner advertises it.
Run a runner covers starting a runner.
A runner takes flights and nothing happens
Section titled “A runner takes flights and nothing happens”What appears. A runner claims flights, and no agent ever runs. gg doctor on that machine reports:
warn executor no agent binary is configured, so this machine will take flights and never start an agentCause. gg never installs an agent. It needs to be told where the agent’s program is, and this machine has not been told.
Fix. Run the fix gg doctor prints, for example:
gg config set executor-binary claude=/usr/local/bin/claudeWhen the agent is already on the PATH, gg doctor names its path in the fix.
A flight has halted
Section titled “A flight has halted”What appears. gg why <flight> prints a line that begins:
HALTED: <reason>Cause. Good Grief could not tell whether an obligation applies or whether it is met, so it stopped rather than guess. This happens when a fact an obligation reads was never reported or holds a value Good Grief does not recognise, when the flight’s rules cannot be determined, or when evidence an obligation asks for cannot be assembled. A halted flight is still open. Gates and decisions: halting explains halts in full.
Fix. Read the reason. A halt caused by a missing or unreadable fact clears by itself when the fact arrives. A halt caused by the rules or by evidence stands until the cause is corrected, usually by changing the envelope, as described in Change the airspace. If the flight should not continue, stop it with gg ground <flight> <why>.
A flight’s work does not land because the credential is read-only
Section titled “A flight’s work does not land because the credential is read-only”What appears. The flight does not land, and the runner reports that the landing was refused:
the credential registered for <repository> carries read and pushing needs write. An envelope declares that a flight may land somewhere; it cannot grant the ability to.Cause. The rules allow the flight to land as a pull request, but landing is done with the organisation’s own credential for the repository, and that credential is registered for reading only.
Fix. Register the repository’s credential with write access:
gg credential add --repo <repository> --scopes read,writeThe token itself must also carry write permission at its provider. Then send it to the machines that need it. Add and send credentials: read or write covers both steps.
The console is slow
Section titled “The console is slow”What appears. The console takes a long time to open, to change tab, or to respond to a key.
Cause. Unknown until measured. The console can record where its time goes.
Fix. Start the console with GG_TIMING set to a file, reproduce what felt slow, quit, and read the file:
GG_TIMING=/tmp/gg-timing.txt ggEach line names a phase, how long it took and, where it explains the time, how many requests it made. Environment variables: GG_TIMING explains how to read it. The file holds phase names, durations and counts, and no flight data, so it can be sent to the Good Grief team with a description of what was slow.
The installer stops because another program is called gg
Section titled “The installer stops because another program is called gg”What appears. On macOS or Linux, the installer stops with:
install.sh: another program called gg is at /usr/local/bin/gg, and installing over it would delete it. Run this again with --as <name>, e.g. --as goodgrief, to install Good Grief's command under another name. Nothing was installed.When it is run at a terminal, it asks instead:
install.sh: another program called gg is at /usr/local/bin/gg.Install Good Grief's command under a different name [goodgrief]:Cause. At least one other program, a Git interface, is also called gg, and the installer will not replace a program that is not Good Grief’s.
Fix. Answer the question with a name, or run the installer again with --as goodgrief (on Windows, -Alias goodgrief). The name is remembered for later updates. Install gg: when another program is called gg explains the options.
When the other gg is only earlier on the PATH, the install continues and ends with:
install.sh: another program called gg is at <path>, earlier on your PATH, so `gg` still runs that one. Install this one under a name of its own with --as <name>, e.g. --as goodgrief, or put /usr/local/bin first.A runner is always installed as gg, so on a runner the installer refuses rather than asking:
install.sh: another program called gg is at /usr/local/bin/gg, and a runner's service runs /usr/local/bin/gg. Remove or rename it first; nothing was installed.