---
title: "Troubleshooting — Robion user manual"
description: "Something is wrong: the symptom, what it means, what to do, where the logs are."
url: "https://robion.app/docs/troubleshooting/"
lang: en
---

# Troubleshooting

Symptom → what it means → what to do, from the user's side. Labels are the desktop's English
strings; a "logs/…" path is under `~/Library/Application Support/Robion` unless said otherwise.

## The window shows "SERVER FAILED"

- The local server could not start; projects and agents are unavailable until it runs. Running
  agents are safe: they live in the pane host, not in the app. The screen names the reason:
  "An older Robion server is running on port 7666 (…, this app needs …)" — quit that app (e.g.
  /Applications/Robion.app) and start this one again, or use another port (`ROBION_PORT`);
  "may still be running on port …" — kill that server process and relaunch; "server keeps
  crashing — last output: …" quotes the line that explains it (since 0.20.7), the whole tail
  is in logs/desktop.log (the app's own record of every server start and exit) and, once a
  server got as far as its logger, logs/server.log. Then **try again**. On a headless Linux
  server run `robion-server doctor` (node 22.13+, the unit, health, tailscale serve, Claude
  Code login).
- The server, the agent tools (the MCP shim in every session) and the pane host run on the
  Node inside the app (since 0.20.7): a node installed with Homebrew is neither needed nor
  used, so a `brew upgrade` that replaces or breaks the system node cannot take Robion down —
  before, that showed up as the Steward reporting "the Robion MCP server failed to connect",
  new sessions without Robion tools, and SERVER FAILED after the next restart. A headless
  Linux server still runs on the system node. `ROBION_NODE=<path>` makes the desktop start the
  server on that node instead (development).

## "FIRST RUN": Claude Code missing

- "Robion needs the tools below on this system. Without them no agent can start." Claude Code
  CLI not on PATH: `curl -fsSL https://claude.ai/install.sh | bash`, then **check again**.
- Nothing else is required: terminals run in Robion's own pane host. (Older versions could run
  them in tmux; that backend and its "tmux missing" notice are gone since 0.20.9, a
  config.json that still says `"paneBackend": "tmux"` is read as the pane host.)

## "Robion's hooks module did not load in this session"

- On a task (desktop: under the terminal's status line; phone: a strip above the chat):
  Claude Code started in the pane but never reported from Robion's
  plugin within a few seconds. Robion learns agent states, the chat, the live context and the
  permission answers from that module ([settings.md](https://robion.app/docs/settings/), "How Robion sees a session"), so without
  it the task's state stays unknown and the phone cannot act on it.
- Causes: Claude Code older than 2.1.287 (`claude --version`; the server log says "too old
  for the hooks module"); a session started by hand outside Robion; a Claude Code update that
  changed the mod API (the session's debug log, `claude --debug`, names the hook the engine
  refused). Update Claude Code and restart the session from Robion (**restart session** on the
  tab). The banner "Claude Code hooks are outdated" and ⚙ → Agents → Claude Code hooks are gone
  since 0.20.28: nothing is installed any more.

## The agent says "Robion was updated, restart this session"

- The pane host keeps sessions alive across updates, so a session started before the update
  still runs the old Robion tools; every tool result carries the note (since 0.19). End the task
  and **resume** it from the home panel's **recently closed** list, or reconnect the robion MCP.

## Every terminal is grey after an update, with a restart button that does nothing

- A banner "replacing the pane host: parking sessions n/N" (then "starting the new host",
  "restoring sessions n/N") means the pane host of the previous version could not be taken over
  and Robion is moving every session to a new one — about a minute for thirty tasks. The
  sessions come back by themselves; **restart session…** and new tasks are refused meanwhile
  ("the pane host is being replaced; wait for the migration to finish"). Do not restart Robion:
  a restart only starts the replacement over. Since 0.20.3 an update normally needs no
  replacement at all: the old host keeps running the sessions and the status line shows **pane
  host awaiting replacement** with **replace now…** ([tasks.md](https://robion.app/docs/tasks/)). If terminals stay grey with no
  banner, ask the agent to add `logs/server.log` as a LOG source and look for "pane host".

## A new task fails with "posix_spawnp failed" (desktop, phone, automations alike)

- The Mac ran out of pseudo-terminals: it has 511, and the pane host of Robion 0.20.25 and
  older leaked one for every pane it ever started (a bug in node-pty's spawn on macOS, fixed in
  0.20.26). After a few hundred tasks and restarts no terminal can start anywhere — not in
  Robion, not in Terminal.app — while the sessions already running are fine; automations fail
  the same way in the INBOX ("failed … posix_spawnp failed").
- Fix: replace the pane host — ⚙ → **Agents** → **Pane host** → **restart…** (0.20.26;
  before that version only the **replace now…** chip after an update did it). Every session
  is parked and resumed on the new host; the leaked terminals are freed when the old host
  ends. Updating to 0.20.26 shows the **pane host awaiting replacement** chip by itself,
  because the host of 0.20.25 is retired like an older one.
- Check: `lsof -n | grep -c /dev/ptmx` near 511 means the pool is full; the one process
  holding most of them is `robion-panehost`.

## The LOG panel shows nothing

- "no log sources defined — an agent adds them with set_log_sources": ask the agent to point
  the panel at a file or a command. "no log lines yet — sources stream only while this panel is
  open": keep it open. Check the **filter (or /regex/)** box and the level filter (**all levels**).
  A command source waits for approval ("…run shell commands…"): **Allow commands**, then confirm.

## A run button stays on "running…"

- Buttons show **not run yet** / **running…** / **stopped**; the output view "finished (exit 0)"
  or "failed (exit N)". A silent button pulses while it runs and refuses a second press. Click
  **stop** in the output view ("close the shell running this command"); before 0.9.2 runs hung.
- A probe shows "paused": "A command probe runs shell commands automatically; it stays paused
  until you allow it for this project" — click **allow** (also ⚙ → **Controls** → **command
  probes**). A red first output line under a probe ("node: command not found") is its own error.

## The agent said "no Robion window shows this project right now"

- The agent tried to show something (a file, a review, a preview screenshot) and no Robion
  window had the project open, so nobody saw it. Select the project in the rail and ask again.

## A cron rule or the Steward did not run

- Automations run in the server. Since 0.20.16 closing the window hides Robion into the Dock
  and the server keeps running; before that, closing the window quit it. **Robion → Quit** (⌘Q)
  still stops everything, and so does a sleeping Mac: a cron minute that passed with the lid
  closed is not caught up. Check the rule's history in **AUTOMATIONS** ([automations.md](https://robion.app/docs/automations/)); an
  always-on remote server ([settings.md](https://robion.app/docs/settings/), "Servers") is the answer for work that must not wait
  for the laptop.

## The phone gets no push

- Pushes are Web Push to the installed phone app only ("notifications work only in the
  installed app"). iOS: Safari Share → "Add to Home Screen", open Robion from its icon; Android:
  **install the app**. Then phone ⚙ → **notifications** → **enable notifications**; "blocked by
  the system" points at the phone's settings. Test with **send a test notification** (phone, or
  desktop ⚙ → **Notifications**). A push comes for a permission or a finished turn, not while
  you are watching the panel.

## Pairing fails, or a server row says "update the server"

- ⚙ → **Remote access** → **pair phone**: the link is single use and valid a few minutes —
  **new QR code** makes another. Needs Tailscale: "Tailscale not found", "Tailscale is not
  running", "the tailnet has HTTPS certificates disabled (admin console → DNS → HTTPS
  Certificates)", "Tailscale Serve does not point at the server — try disabling and enabling
  again". **generate a new token** signs out every device: pair the phone again. On a Linux
  server `robion-server pair` prints a one-time link; HTTP 401 = wrong or missing token.
- **update the server (vX)** in ⚙ → **Servers** (rail: "update this server (protocol
  mismatch)"): the server runs an older release. **update to X** runs `robion-server update` on
  the box (builds beside the running version, switches atomically, restarts; agents survive);
  or run it over ssh. Not back after 20 minutes: `~/.local/share/robion/logs/update.log` on the
  box. A parked server reconnects by itself since 0.12.12 (/health probed every 30 seconds).

## No sound on a Linux box after installing the server

- The box is also a desktop (a Raspberry Pi with a monitor, say) and after the install its
  HDMI sound is gone: apps play into "Dummy Output". The installer turns on
  `loginctl enable-linger` so the server starts at boot without a login; linger also starts
  PipeWire and WirePlumber at boot, where they probe the HDMI card while the login screen is
  still taking the display over. The failed probe is cached, so the output never comes back
  by itself — a reboot helps only by luck. On the box: `systemctl --user restart wireplumber`
  — sound is back at once, nothing else changes. For good: a drop-in that makes WirePlumber
  wait for the display, or a user unit that restarts it once the graphical session is up
  (docs/linux-server.md, Troubleshooting). A box without a monitor is not affected. Keep the
  server a user unit: `robion-server` and `doctor` assume `systemctl --user`.

## A message on the phone stays "sent · waiting for the agent"

- Before 0.20.16 the bubble hung for good for a prompt of 20+ characters (Claude Code stores
  such a paste inside `<pasted_content>` tags, which the phone did not recognise as its own
  text) and for a slash command such as `/clear` (never written as a chat row). Since 0.20.16
  the server strips the tags from the transcript, the bubble goes when the agent's turn ends
  or after 20 minutes, a tap hides it, and a slash command shows none. The message itself
  reached Claude Code in every case — the bubble was only the phone waiting for a confirmation
  it could not match.

## A task hangs on "waiting" after Esc or No on a permission dialog

- Since 0.12.5 Esc or No sets the task idle at once; Esc before the first word of a reply ends
  the turn within seconds. If it still waits: **answer in the terminal** — the prompt is there,
  the answer goes as keystrokes. "<name> needs your input" on a fresh pane came from Claude
  Code's blocked background jobs (ignored since 0.12.3): `claude rm <id>` removes a stale job.

## The task shows "working" only while a tool runs, or "interrupted" after every reply

- Seen on Claude Code 2.1.293 and 2.1.294 with Robion up to 0.20.36: a prompt never turned the
  task yellow-dotted "working", a finished reply became "interrupted" a few seconds later, a
  permission dialog never showed as "waiting" and the phone got no card for it. The events
  Robion read the state from had stopped reaching its hooks module in sessions started on those
  builds. **Fixed in 0.20.37**: the module reads the state from Claude Code's own engine events.
  Sessions started before the update keep their old module until they end — restart the
  session (Task → Restart session) to get the new one.
- A permission dialog now shows as "waiting" within two seconds of appearing (Robion reads
  Claude Code's session file), and the phone's allow / deny types the answer into the terminal
  as the desktop does.

## The task says "done" while the agent is still writing

- A prompt typed while the agent works is queued by Claude Code and taken up when the running
  turn ends. Before 0.20.37 the task went "done" at that moment and stayed "done" through the
  whole reply to the queued prompt; now it goes back to "working" the moment the agent takes the
  prompt up.
- A "done" that flips back to "working" within a blink (a finished background task waking the
  agent up) no longer reaches the phone, the Inbox or the timeline: "done" is announced only
  once it has stood for 400 ms.

## The phone shows an empty permission card while the terminal shows the agent's question

- Before 0.20.24: the phone (or the rail) said "the agent asks for permission" with nothing
  under it but **allow** / **deny**, while the terminal sat in an AskUserQuestion dialog.
  That happened when the session asking was not the one the pane was started with — a session
  with a new id that continues the pane's conversation (the Claude app or Remote Control
  driving a fork of it, or the terminal itself after a resume whose SessionStart Robion did
  not see). Robion took such a session as a fork, dropped the question's cards, and the
  dialog's own "needs your permission" notice then showed as a bare permission; **allow**
  typed `1` into the terminal.
- Since 0.20.24 the cards stay, the notice keeps the "the agent asks" state, and answering
  reads the terminal first: when the dialog is there (the terminal asked), the answer goes in;
  when it is not (another client asked), the phone says "the question is not in this task's
  terminal — the session that asked runs in another client; answer it there". The card also
  carries **answer in the terminal**, which opens the **terminal** tab with its key bar (1–3,
  Enter). To tell which case you are in: logs/server.log has "a fork of the pane's
  conversation reports in" with both session ids.

## A closed task offers "start again" instead of "resume"

- "the session left no transcript (it was closed before its first message), so there is nothing
  to resume — a new task starts with the same title and brief." Click **start again** in the
  home panel's **recently closed** list; **resume** would continue the same conversation.

## Claude Code asks "do you trust this folder?" in a new project

- Claude Code's own dialog in the terminal. A project created from the phone or the ⊕ button
  is pre-trusted (0.12.11); a cloned or picked folder keeps the question. Answer it in the
  terminal; on the phone use the key bar (Esc, Tab, ⇧Tab, arrows, ⏎, ^C, 1–3) — the chat
  shows a hint pointing at the terminal when a fresh Claude Code stays silent for 10 seconds.

## A crash, a black window or "panel crashed"

- Since 0.19 a crash shows a fallback: "the workspace crashed" (other projects, the Inbox and
  settings keep running; the saved layout is the usual culprit) or "Robion crashed" (the server
  and the agents keep running): **try again**, **start from the default layout**, **reload the
  window**, **copy the error**; the error is in logs/desktop.log. "panel crashed": the rest of
  the app keeps running — close the tab, or reopen it after the bug is fixed.

## Where the logs are

- `~/Library/Application Support/Robion/logs/` (Help → **Open Logs Folder**, since 0.20.8):
  `server.log`, `desktop.log` (renderer errors,
  crash screens), `events.jsonl` (hook payloads, only with ⚙ → **Application** → **Log hook
  events**), `setup-<branch>.log` / `teardown-<task>.log` (worktree scripts). Ask the agent to
  add them as LOG sources. Linux server: `~/.local/share/robion/logs/` (with `update.log`) and
  `journalctl --user -u robion-server`. The Steward's files: `…/Robion/steward/`.

## The update chip, or an update that failed

- Status line: "checking for updates…", "Robion X · downloading N %", "Robion X is ready" with
  **restart** (installs and starts Robion again; agents and terminals keep running and
  reconnect; until then it installs when you quit) and **hide** (the app menu keeps "Restart and
  Install"; also ⚙ → **Servers** → **restart and install X**). Checks repeat every 6 hours and
  after wake, also while a downloaded version waits: a newer release replaces the waiting one
  (since 0.20.19), and **Check for Updates…** stays in the app menu next to "Restart and
  Install". A failed check says why (offline, release not published yet) — try later.

## Questions about telemetry

- ⚙ → **Privacy** → **Send anonymous usage statistics** lists what is sent and what never is;
  the switch takes effect at once. Details in [settings.md](https://robion.app/docs/settings/) (Privacy) and TELEMETRY.md.

## Maker Pack missing or outdated

- ⚙ → **Agents** → **Maker Pack**: **installed** / **update available** / **not installed**,
  with **install**, **update**, **remove**; the banner "Maker Pack has an update" → **update**
  runs `claude plugin update` (agents pick it up next session). The design wizard needs pack 0.26.

## The agent cannot reach main from a worktree

- By design: a task in its own worktree runs `claude --worktree` and "the main checkout is out
  of the agent's reach". The agent commits on its branch and asks for a review; you **merge**, **update** or
  **remove** the checkout in the side panel's **tasks** section. An agent that must touch main
  needs a task started with **main checkout** picked in the segment next to **new task**.

## Conflicts after "update" of a checkout

- The row shows "conflict · N" and "the rebase onto main stopped on these files:". Choose
  **abort rebase**, **open a shell** (fix by hand, then **continue**) or **let an agent resolve
  it** (a task told to resolve every conflict keeping both intents, run the tests, not push).

## A merge fails in a hook with "npm: command not found" (or another tool)

- Before 0.20.1 the merge ran git with the app's bare PATH, so a husky / pre-commit hook could
  not find npm. Since 0.20.1 git, worktree setup scripts, run buttons and probes get the PATH
  of your login shell (`$SHELL -ilc`), the node the server runs on and Homebrew. A tool still
  missing: check that your login shell finds it (`zsh -ilc 'command -v <tool>'`), then restart
  Robion, or click ⚙ → **Agents** → **check again**, which re-reads that PATH. The dialog
  shows what the hook printed under the message. After a refused squash or a merge that failed
  half-way, main is put back when it was clean; otherwise the merged changes stay staged there
  — commit or reset them. A conflict with a moved main never lands in the main checkout: the
  branch is updated in its worktree first and the TASKS row shows the conflict ([checkouts.md](https://robion.app/docs/checkouts/)).

## "server not connected" in the new checkout dialog

- The **new checkout** request got no answer from the server. Check the status line ("server
  disconnected", "connecting to server…"), wait for "server connected", try again. "the checkout
  list is not loaded" in the end-task dialog is the same case; the worktree stays.

## Rate limits in the rail widget

- The **USAGE** widget shows the 5h and week windows with "in <time>" until reset. "limits: sign
  in in Claude Code (/login)", "limits: stale", "limits: endpoint rejected the request" →
  **retry**; "limits off" = ⚙ → **Application** → **Track subscription limits** is off. "limit
  exhausted: 5h — agents are stalled", "reset in …": Claude Code waits for the quota to reset
  and prompts finish on their own, just later — nothing to fix but time.
