Troubleshooting: Look Up an Error
Troubleshooting: Look Up an Error
Section titled “Troubleshooting: Look Up an Error”Start here when a
bobcommand fails. Search this page for the text the command printed — each entry heading is the verbatim message (or the start of it), followed by the cause, the fix, and the page that owns the feature. (Back to how-to guides.)
Parts of a message that change from run to run — a port, a hostname, a file
path — are written as <port>, <host>, <path>. Search on the fixed words
around them.
This page is checked against the code. Every entry declares the file that
prints its message in an emitted-by comment. make check-troubleshooting
fails when that text no longer exists in that file, so an entry can’t go stale
after the message is reworded. Adding an entry is covered in
Adding an entry.
Errors, by message
Section titled “Errors, by message”Dashboard did not become healthy on <host>:<port> within 5s
Section titled “Dashboard did not become healthy on <host>:<port> within 5s”Cause. bob warp viz (or bob viz) started the project’s dashboard server,
but the server didn’t answer. bob warp viz prints the tail of the server’s log
under the error (Server output (…/dashboard-<project>.log)). The log names the
real cause, usually a port conflict.
Fix. Read the log lines printed under the error. For the common case, where
this project’s own dashboard holds the port on the other bind, see the next
entry. The full log is $XDG_STATE_HOME/bob/dashboard-<project>.log (default
~/.local/state/bob/).
More: Warp-drive troubleshooting (#2560).
<project>'s dashboard is already running on port <port> on another bind
Section titled “<project>'s dashboard is already running on port <port> on another bind”Also printed by the server as
<project> dashboard is already running on port <port> bound to <address>, not 127.0.0.1 (localhost).
Cause. An earlier bob warp viz --tailnet is still serving this project on
the Tailscale address, so plain bob warp viz (localhost) can’t start a second
server on the same port. The reverse no longer refuses: --tailnet over this
project’s own localhost server restarts it on the Tailscale address (#2917).
Fix. Reuse the running server, or replace it:
bob warp viz --tailnet # reuse the tailnet server (bob viz --tailnet for the /bob page)bob dash serve --stop <project> # or stop it, then re-run the command you wantedbob doctor lists the server holding the port, with its bind and age, in its
dashboards section (see the next entry).
More: Warp-drive troubleshooting (#2560).
INFO dashboards: <n> running, <m> flagged
Section titled “INFO dashboards: <n> running, <m> flagged”Printed by bob doctor (and bob status --scope host). Each server’s line
ends with its clickable /warp URL, the MagicDNS name for a tailnet-bound
server, and the section closes with Fleet: <url>/bob while any server is up
(#2639). Each flagged server is marked ! on its line, with the reason:
started before the current deploy: the server started before the deploy recorded in~/.claude/.bob-version, so some of its loaded code may be old.running code older than the deployed server.js:server-fresh.shsays the server is stale.can no longer run gh: the server has lostgh. Only a restart from a fresh shell fixes it.bound <bind>, but <project> last asked for <bind>: the server is on localhost and the project last asked for the tailnet, or the reverse. This is the #2560 case, before it breaks abob warp viz.
Cause. Dashboard servers are long-lived. bob dash serve, bob warp viz,
bob warp viz --tailnet and bob viz leave them running after the command
returns. Nothing else stops them.
Fix. Run the command printed after Fix:, or stop every one:
bob dash serve --stop <project> # every server for that project, any port or bindbob dash serve --stop --all # every BoB dashboard server on this machineThe section is informational: it never changes the bob doctor verdict or
exit code. bob doctor --json carries the same data under dashboards
(bob-dashboard-servers/1): each record’s urls is {magicdns, ip, localhost}
for its /warp page, and fleet is the /bob page’s set (#2639).
More: Warp-drive from the command line (#2563).
machine: could not resolve current host (hostname=<host>) to a fleet entry
Section titled “machine: could not resolve current host (hostname=<host>) to a fleet entry”Cause. No fleet entry in machines.json matches this machine’s hostname.
The usual trigger is bob operator init --link without migrate. The operator
repo’s placeholder machines.json (one example-laptop entry) then shadows your
real fleet, and bob doctor and fleet snapshots also report example-laptop.
Less often, the machine is new and has no entry yet.
Fix. If you just linked an operator repo, park the placeholder so the real fleet is read again, then migrate on purpose:
cd ~/projects/bob-operatorgit rm --cached -q machines.json 2>/dev/null; mv machines.json ~/machines.scaffold.jsonnode ~/.claude/scripts/fleet/machine.js whoami # your real entry againIf the machine is new, add its entry to the operator repo’s machines.json.
More: Recovery: the scaffold is shadowing a live fleet.
operator-resolve: WARNING: <file> read from the legacy BOB_SOURCE location <path>
Section titled “operator-resolve: WARNING: <file> read from the legacy BOB_SOURCE location <path>”Cause. Operator data (machines.json, ports.json, the project manifests)
is still read from the BoB source checkout instead of the operator repo (#2270).
It still works, but the fallback retires on 2026-10-31.
Fix. Create and link the operator repo, then move the data into it with history:
bob operator show # is an operator resolved? exit 3 = nobob operator migrate # dry run: what would movebob operator migrate --applyMore: Set Up Your Operator Repo.
[deploy] REFUSED: live-session — a Claude Code session is running on this machine
Section titled “[deploy] REFUSED: live-session — a Claude Code session is running on this machine”Exit code 4. bob update refuses for the same reason. Both then print
QUEUED: the deploy or update is recorded and BoB runs it itself (#3162).
Cause. Rewriting settings.json while Claude Code sessions are running
silences every hook in those sessions until they restart. So deploy.sh refuses
and writes nothing now. The message names each live session’s project and PID.
Fix. Nothing to run. The refusal is queued in ~/.claude/.deploy-pending,
and BoB finishes it at the first safe moment:
- the SessionEnd hook of the last live session (it waits for that session to exit);
- the next
bob tick; - the next fleet-snapshot timer run.
The drain takes the bob tick lock and never runs while any session is live.
It deploys the machine’s declared channel: a pinned machine deploys its tag
(#3171). It then runs bob doctor and sends the result through bob notify.
Until then bob doctor, bob status --scope host and bob viz show
deploy queued since <time>. Check it or drain it by hand:
node ~/.claude/scripts/fleet/deploy-pending.js status # exit 3 = queuednode ~/.claude/scripts/fleet/deploy-pending.js drain # exit 3 = a session is still liveA drain that fails keeps the record, notifies once and retries at the next
safe moment. The --force-live override (BOB_DEPLOY_FORCE_LIVE=1) still
exists for a deliberate deploy under live sessions. Restart every session it
names afterwards.
Only real sessions are counted (#2763). The daemon’s pre-warmed spare slot
(claude bg-spare, or claude bg-pty-host …/spare/…) is listed as ignored and
never causes a refusal.
Find the named session
Section titled “Find the named session”To deploy now rather than wait for the drain, end the sessions the refusal names. It lists one line per session:
warp-drive run: <project> (<phase>) pid <pid> — <path>claude process: pid <pid> — <command>-
Print what the guard counted and what it ignored:
Terminal window node "$BOB_HOME/scripts/fleet/settings-hooks-reconcile.js" live-check --json \| jq '.live | {projects, pids, ignored}'live.projectsandlive.pidsare the sessions that block the deploy.live.ignoredis the daemon’s own processes. Leave those alone. -
Find the terminal of each counted PID:
Terminal window ps -o pid=,tty=,lstart=,args= -p <pid>The second column is the terminal, for example
pts/5. -
Match that terminal to a tmux pane:
Terminal window tmux list-panes -a -F '#{session_name} | #{pane_tty} | #{pane_current_command} | #{pane_current_path}'The line with
/dev/pts/5names the tmux session, for examplewarp-myproject-fp-42 | /dev/pts/5 | claude | /home/me/projects/myproject. A PID with no matching pane runs in a plain terminal window or over SSH. -
End the session. For a warp-drive run, stop it from the project directory. For any other session, attach and exit Claude:
Terminal window bob warp stop # a warp-drive run, from <path>tmux attach -t <session_name> # any other session, then type /exit -
Check that nothing is counted, then re-run the command that was refused:
Terminal window node "$BOB_HOME/scripts/fleet/settings-hooks-reconcile.js" live-check --strictExit code 0 means no session is live.
More: Reconcile on deploy (#2040) · Queued deploys.
INFO deploy queued since <time> by <requester> …
Section titled “INFO deploy queued since <time> by <requester> …”Printed by bob doctor and bob status --scope host. bob viz shows the same
line for each machine. It is never graded.
Cause. A deploy or bob update was refused because a Claude Code session
was live, and BoB queued it (#3162). The line stays until the queued deploy
has run. last attempt failed: … means a drain ran and failed; the record is
kept.
Fix. Nothing, normally. The deploy runs when the last session ends. If the
line names a failure, read ~/.claude/logs/deploy-drain.log or run the drain
once by hand to see it:
node ~/.claude/scripts/fleet/deploy-pending.js drainbob doctor # the line is gone once the drain succeededbob update: REFUSED — live-session: a Claude Code session is running on this machine
Section titled “bob update: REFUSED — live-session: a Claude Code session is running on this machine”Exit code 4. Nothing was changed.
Cause. bob update moves the source checkout and then deploys. Before it
moves anything it reads the hook wiring the target tag declares, and refuses
only when a Claude Code session is running on this machine and deploying
that tag would rewrite the settings.json hooks (#2746). A target whose hooks
are already deployed is never refused.
bob update has no override. --force-live and BOB_DEPLOY_FORCE_LIVE=1
work on scripts/deploy.sh and settings-hooks-reconcile.js apply only.
bob update ignores both.
Fix. Nothing to run. The refusal then prints QUEUED: the update is
recorded in ~/.claude/.deploy-pending, and BoB runs it itself when the last
live session ends (#3162), exactly as for a
refused deploy.
To update now instead, find each named session, end it, and run:
bob update --dry-run # shows the target and whether a session is still livebob updateMore: Reconcile on deploy (#2040, #2126) · Updating a machine.
bob update: REFUSED — <branch> @ <sha> is not an ancestor of <tag> (<sha>) — an update never rewinds or rebases
Section titled “bob update: REFUSED — <branch> @ <sha> is not an ancestor of <tag> (<sha>) — an update never rewinds or rebases”Exit code 3. Nothing was changed.
Cause. bob update only moves a checkout forward to a release tag. This
checkout already holds commits that are newer than the tag, so there is
nothing to move forward to. It happens on a machine whose checkout follows
master, where work merges between releases. It also appears straight after a
live-session refusal
has been cleared, as the next gate.
Fix. First see which source this machine runs, and how far the checkout is ahead of the newest tag:
jq . ~/.claude/.bob-version # version, channel, source_sha, deployed_atbob update --dry-run # the tag it would move to; writes nothingThen choose one:
scripts/deploy.sh # run this machine on its current checkoutbob release # or cut a release at HEAD first, then: bob updatescripts/deploy.sh runs from the source checkout. It
records the checkout’s commit in .bob-version with channel checkout. Use
bob release when the machine has to stay on the stable channel.
More: Updating a machine (#2046).
bob-release: REFUSED — release notes for v<X.Y.Z> are not finished: …
Section titled “bob-release: REFUSED — release notes for v<X.Y.Z> are not finished: …”Exit code 3. Nothing was bumped, tagged or pushed.
Cause. This repo keeps release notes (it has docs/releases/), and the notes for the version
the release is about to cut are missing, still status: draft, carry a <!-- draft: … -->
marker, or have an empty section. The message lists each problem after the colon.
Fix. Draft the notes if they are missing, finish them, then check them:
bob release notes --draft # writes docs/releases/vX.Y.Z.md as a draftbob release notes check --release vX.Y.Z # names every section still to finishDelete every marker, set status: final, and run bob release again. The notes may stay
untracked: the release commits them.
More: Release notes (#3060).
bob release notes site: REFUSED — the public pages carry <n> private value(s): …
Section titled “bob release notes site: REFUSED — the public pages carry <n> private value(s): …”Exit code 3. Nothing was written or published.
Cause. A public release page would carry something private: an operator literal, a machine
name from the fleet manifest, an email address, a link into the (private) repository, or an
operator project name. Each hit is named as <page>:<line> "<value>" (<why>).
Fix. Remove the value from the notes file named by the page (vX.Y.Z/index.html →
docs/releases/vX.Y.Z.md). Put issue links only in a trailing parenthesis — the public form drops
it — and name machines by role (dev-laptop, farm-worker). Then build again:
bob release notes siteMore: Release notes (#3060).
warp start: preflight failed (exit <n>) — not starting. Verdict:
Section titled “warp start: preflight failed (exit <n>) — not starting. Verdict:”Exit code 1 from bob warp start.
Cause. bob warp start runs bob preflight (the host check from
bob doctor plus project readiness from bob ready --dry-run) before creating
the tmux session. A check failed. The verdict printed below the message names
each failed check (a - line) and its fix command. Host drift alone does not
fail the gate (#3160): a ~ line is an advisory, see the next entry.
Fix. Run the fix commands in the verdict, then check again before retrying:
bob preflight # the same gate, on its ownbob ready # converge the project (idempotent)scripts/deploy.sh # when a host: check failed (a "-" line)More: Preflight gate.
~ host:behind: BOB_HOME runs <sha>; source is at <sha> … (advisory — does not block)
Section titled “~ host:behind: BOB_HOME runs <sha>; source is at <sha> … (advisory — does not block)”Printed by bob preflight and bob warp start. The exit code is unchanged.
Cause. Nothing is wrong with the project. A ~ line is an advisory (#3160):
the gate names it with its fix and passes. host:behind means the bigbrain
checkout has commits that were not deployed to ~/.claude yet. Other
advisories are host:symlinks, host:toolchain, project:labels and
project:ports. Before #3160 any of these stopped every project on the
machine.
Fix. None is needed to work on the project. To clear the line, run the fix
it names. If a Claude Code session is live, deploy.sh queues the deploy and
BoB runs it when the last session ends (#3162):
scripts/deploy.sh # host:behind — bring ~/.claude up to the checkoutbob doctor # confirm: "Converged" (or "deploy queued since …")More: Preflight gate · check-host.
stale <path> — content differs from the deployed commit <sha>
Section titled “stale <path> — content differs from the deployed commit <sha>”Printed by bob doctor under FAIL surfaces:. bob preflight reports it as
the failed check host:surfaces, and bob ready as the host blocker.
Cause. A file under ~/.claude is not what the last deploy put there. The
host check compares ~/.claude with the commit recorded in
~/.claude/.bob-version, not with the bigbrain working tree (#3160). This is
the one kind of host drift that blocks: the file was edited or deleted in
~/.claude, or a deploy was interrupted.
Fix.
scripts/deploy.sh # under a live session this is queued and BoB finishes it (#3162)bob doctor # "PASS surfaces: … match the deployed commit"More: check-host.
PREFLIGHT RE-CHECK — ADVISORY (#3160): the host check on <machine> reported …
Section titled “PREFLIGHT RE-CHECK — ADVISORY (#3160): the host check on <machine> reported …”Printed in the response to next_chunk or continue_yes during a warp-drive
run. The run continues.
Cause. The host check that runs between chunks found something on the
machine. In a project other than bigbrain the re-check is report-only (#3160):
it records the finding on state.preflight.rechecks[], files no todo and does
not stop the run. Only a run on the BoB source checkout is stopped by a hard
host finding mid-run.
Fix. Nothing from inside the run. After the run:
bob doctor # names each finding and its fixMore: Preflight gate.
Warp-drive is in phase "<phase>". Commits are only allowed during: …
Section titled “Warp-drive is in phase "<phase>". Commits are only allowed during: …”Cause. The commit gate hook blocked a git commit outside the committing
phase. The whole Bash call was blocked, including any other commands bundled
with the commit.
Fix. Finish the current phase (for example, fire tests_passed in
testing), then commit on its own. bob warp log shows the phase history if a
phase was skipped.
More: Warp-drive troubleshooting.
forge: degraded / forge: unreachable
Section titled “forge: degraded / forge: unreachable”Printed by bob forge health (exit 3 = degraded, 4 = unreachable, 5 = unknown).
Cause. Recent gh calls failed often enough that GitHub is classed as not
operational. While it is, an empty gh result (no issues, no PRs) may just be
a failed call.
Fix. Check the classification and the evidence behind it, and don’t act on empty results until it recovers:
bob forge health # state, reason, recent ok/totalgh auth status # rule out an expired token firstMore: Forge health: States.
[forge-queue] not created yet — the live call failed
Section titled “[forge-queue] not created yet — the live call failed”Also gh: <handle> is a queued-issue handle that has not been created yet.
Cause. The gh shim couldn’t reach GitHub, so it spooled the issue write to
the forge queue instead of losing it. The printed handle stands in for the
issue until the queue replays.
Fix. Nothing is lost. Once bob forge health is operational again, replay
the queue:
bob forge queue statusbob forge queue replay # dry runbob forge queue replay --applyMore: The write queue.
Server failed to start. Last 20 lines of log: then Missing script: "dev"
Section titled “Server failed to start. Last 20 lines of log: then Missing script: "dev"”Cause. bob dev up (and the warp-drive prerequisite) started the command in
dev.json, and it exited. When the log shows npm’s Missing script: "dev" in a
CLI or library repo, bob ready / bob init has generated a dev.json with
npm run dev for a project that has no dev server (#2463, open).
Fix. Read the log tail printed under the message. For the CLI-repo case,
delete the generated dev.json (it is gitignored there) and re-run. With no
dev.json, dev-up has nothing to start.
rm dev.jsonbob dev upMore: dev.json Manifest.
Troubleshooting elsewhere
Section titled “Troubleshooting elsewhere”Feature pages keep their own troubleshooting sections. They are linked here rather than copied, so each one has a single source:
| Area | Section |
|---|---|
| Warp-drive loop (phases, gates, hooks, state file) | Warp Drive Guide → Troubleshooting |
Parallel worktrees (bob fork) |
cdfork Guide → Troubleshooting |
| New machine bootstrap | New Machine Setup → Troubleshooting |
| Promotion ladder, deploys | Set Up dev → test → prod → Troubleshooting |
| Runbook generation | Generate a Runbook → Troubleshooting |
| Provisioning recommendations | Orchestrator → Troubleshooting |
| Token monitoring | Token Monitoring → Troubleshooting |
| Everything else, by area | Handbook §16 Troubleshooting |
| Incidents, handoffs, onboarding | Incident Response · Agent Handoff · Project Onboarding |
Adding an entry
Section titled “Adding an entry”- Copy the error exactly as printed. Use it (or its fixed prefix) as the
###heading, with<placeholders>for the parts that vary. - Find the file that prints it and add at least one marker under the heading.
The text after
::must appear verbatim in that file, so choose a fixed run of words with no variable parts:<!-- emitted-by: scripts/fleet/machine.js :: could not resolve current host (hostname= --> - Write Cause, Fix (commands first) and More (a link to the page that owns the feature). Link to existing troubleshooting sections rather than copying them.
- Run
make check-troubleshooting.