Common issues
Missing API key
Missing API key
ANTHROPIC_API_KEY) instead. See AI Providers.Chat connection refused
Chat connection refused
ws://localhost:9200/ws/chat is refused.Fix: Make sure the HQ is running. If using Desktop, check that the HQ process is healthy from the app. If running standalone, check the server logs for “HQ channel server listening on port 9200”.Unknown agent error
Unknown agent error
GET /agents on the Management API) and make sure the name matches a deployed squad member.Conversation sync and resumable chat
Conversation is busy
Conversation is busy
409 with conversation_busy, or chat returns an error
frame with the same code. The error may include an activeTurnId.Fix: Refresh GET /mobile/v1/conversations/:id and use its activeTurnId. Replay from
your last applied sequence, then either send resume for that same turn ID or send cancel
for it. Wait until a terminal frame is durable and the refreshed summary no longer has an
active turn before retrying the mutation or starting another turn. Do not work around the
lease by sending the prompt again with a new ID; that can duplicate model work.If the error says The previous turn is still settling, the HQ is waiting for the
previous provider run to finish. After cancellation, cleanup can continue even when the
conversation summary no longer has an active turn. Wait briefly before retrying. Legacy
chat also rejects a second response while the same conversation is running on another
connection.No active legacy request for this connection
No active legacy request for this connection
Chat has a sequence gap after reconnecting
Chat has a sequence gap after reconnecting
seq than expected, or a socket
closed while a resumable turn was running.Fix: Keep the highest sequence you applied. Request
GET /mobile/v1/agents/:agentId/conversations/:conversationId/events?sinceSeq=<last-seq> and
apply the returned entries in ascending sequence order. If the same turn is still active,
send this frame with the original turn ID:message with a new turn ID.Conversation revision conflict
Conversation revision conflict
PATCH or DELETE returns HTTP 409 with revision_conflict after another
client changed the conversation.Fix: Replace your cached conversation summary with the complete summary in
details.current. Reapply the intended title or metadata change to that current value, then
retry with its revision in a quoted If-Match header. Do not automatically retry a delete
without first showing or checking the newer state.Mobile client is rate limited (429 or 4429)
Mobile client is rate limited (429 or 4429)
429, a structured error reports rate_limited, or a relayed
WebSocket closes with code 4429.Fix: Stop reconnecting or retrying in a tight loop. Honor the HTTP Retry-After header or
the retry delay supplied by the relay, then reconnect once. If no delay is supplied, use
exponential backoff with jitter and reset it after a stable connection. Preserve your last
applied sequence so the eventual reconnect replays the gap instead of resending prompts.Relay cannot reach the HQ (502 or gateway_offline)
Relay cannot reach the HQ (502 or gateway_offline)
502, chat reports gateway_offline, or the phone can
reach Dash but not the paired HQ.Fix: Bring the HQ machine online and make sure the Dash HQ is running, then let
its outbound relay connection re-establish. Until health succeeds, show cached conversation
history as read-only: do not queue metadata mutations, deletes, or prompts as though they were
accepted. Once connected, refresh summaries and replay from the last sequence. Re-pair only
if the device credential was actually revoked; an ordinary offline period does not require it.My synced conversations are read-only
My synced conversations are read-only
Message saved for recovery
Message saved for recovery
A conversation says Active on another device
A conversation says Active on another device
Older conversations appear under On this Mac
Older conversations appear under On this Mac
Rename or delete says the conversation changed
Rename or delete says the conversation changed
Update Dash appears in chat
Update Dash appears in chat
A project session does not open
A project session does not open
Secrets and credentials
Provider key not taking effect
Provider key not taking effect
Credentials unreadable after copying ~/.dash elsewhere
Credentials unreadable after copying ~/.dash elsewhere
~/.dash/gateway/credentials.enc, decrypted with the key in ~/.dash/gateway/secret.key.Fix: If you copy ~/.dash to another machine, copy both files together — credentials.enc can’t be decrypted without its secret.key. If secret.key is lost, delete credentials.enc and re-enter your keys on the AI Providers page.Remote access (relay)
Dash for iOS can't reach your Dash account service
Dash for iOS can't reach your Dash account service
Couldn’t reach your Dash account service. Check your connection and try again.Fix: This means loading your enrolled HQs failed — the app never confuses this with “no HQs enrolled,” so seeing this message doesn’t mean your account is empty. Check the phone’s connection and tap Retry. If it persists, confirm the machine that hosts your Dash account service is reachable from the internet.
Dash for iOS shows no HQs linked to your account
Dash for iOS shows no HQs linked to your account
No HQs linked to your account yet. Open Desktop → Settings → Devices → Remote access to enroll this machine.Fix: Open Settings → Devices → Remote access in Desktop on the machine running your HQ, sign in with the same Dash account, and click Create HQ. Then tap Refresh on that same empty screen in the app — the new HQ appears without signing out or restarting. (Once the list has HQs in it, pull down on the list to refresh instead.)
Dash for iOS says an HQ needs to be re-enrolled
Dash for iOS says an HQ needs to be re-enrolled
This HQ needs to be re-enrolled from Desktop before app access works.Fix: This HQ’s Remote access setup on Desktop predates this app’s account sign-in support, so it never registered the app’s chat capability. Open Desktop on the machine that runs this HQ — it updates the HQ’s app access automatically on launch — then try the HQ again in Dash for iOS.
Desktop cannot create a local pairing code
Desktop cannot create a local pairing code
Pair Device asks to switch to the local HQ
Pair Device asks to switch to the local HQ
Sign-in failed
Sign-in failed
Select an organization
Select an organization
Create HQ is missing or fails
Create HQ is missing or fails
Remote access stopped working after a while
Remote access stopped working after a while
QR code still pairs over the local network
QR code still pairs over the local network
Phone can no longer connect after a revoke
Phone can no longer connect after a revoke
The address I want is already taken
The address I want is already taken
Approving a new browser session times out or is declined
Approving a new browser session times out or is declined
Approval declined. You can try again from the HQ list.
The code expired. Try again from the HQ list.Fix: This screen only appears on accounts that already have a Dash for iOS device signed in — new browser sessions need one of those devices to approve them. Approval declined means someone tapped Deny on the phone; The code expired means nobody approved it within the time limit. Either way, go back to the HQ list and sign in again to get a fresh code, then open Dash on the phone, go to Settings → Approve a device, and scan it before it expires.
Dash for iOS says a browser's code has expired
Dash for iOS says a browser's code has expired
This code has expired. Ask the device to try again.Fix: Approval codes expire a few minutes after they’re generated. Ask whoever is waiting on the browser to reload the HQ list (or sign in again) to get a fresh code, then scan the new one right away. A code that’s still valid instead shows a confirm sheet reading
Allow "<device>" to access <HQ>? — tap
Approve or Deny there.Remote HQs
Desktop is still using the local HQ
Desktop is still using the local HQ
Remote HQ is unhealthy
Remote HQ is unhealthy
VPS deployment fails
VPS deployment fails
git, node, npm, and systemctl --user
available. If the relay URL or HQ id is wrong, fix those fields and
deploy again.Chat opens but messages do not stream
Chat opens but messages do not stream
wss:// for HTTPS relays and point at the same HQ host as the
management URL.Tool errors
Workspace not found
Workspace not found
workspace path in your agent config exists. Dash creates the workspace directory automatically at startup, but if the config path is wrong, the tool may be looking in the wrong place.Path escape blocked
Path escape blocked
read tool blocks paths that resolve outside the workspace. This is intentional — use absolute paths or paths relative to the workspace root.Command timeout
Command timeout
bash tool has a 30-second timeout. Long-running commands are killed after this period. Break long operations into smaller steps or increase the timeout in the source code if needed.Output truncation
Output truncation
bash tool limits output to 100 KB. If a command produces more output, pipe it through head, tail, or redirect to a file and use read to retrieve specific sections.Plugins
Plugin not loading
Plugin not loading
SKILL.md). If hand-editing, make sure the plugin has an entry in ~/.dash/gateway/plugins/config.json with "enabled": true. See Plugins.Code components inert until trusted
Code components inert until trusted
bin/ executables, or providers do nothing, even though the plugin is enabled.This is intentional. A freshly installed plugin is enabled but not trusted — its skills and commands work, but its code and credential components stay inert until you trust it. Click Trust on the plugin card, review the confirmation listing what will run, and confirm. See the Security model.Slash command /plugin:command not found
Slash command /plugin:command not found
/<plugin>:<command> doesn’t resolve.Fix: Commands are namespaced as /<plugin>:<command> — a plugin named research with commands/triage.md is /research:triage, not /triage. Confirm the plugin is enabled (commands need only enabled, not trust) and Loaded on the Plugins screen, and that the file lives in the plugin’s commands/ directory. See Invoking each component.OpenRouter model list looks outdated
OpenRouter model list looks outdated
Plugin provider model not in the dropdown
Plugin provider model not in the dropdown
<id>/<model-id> models become selectable. See Provider credentials.Install failed
Install failed
POST /plugins/install (or the Install button) returned an error.Fix: The response code tells you why. 404 — the source wasn’t found (a missing repo, dead URL, or unknown name); check the source string. 409 — a plugin with that name is already installed; remove it first or install under a different name. 422 — the plugin is invalid, corrupt, or the security scan flagged it as dangerous and refused it; inspect the source before retrying. See What the errors mean.Removed plugin still listed
Removed plugin still listed
~/.dash/gateway/plugins/ directly, trigger a rescan with POST /plugins/reload (or restart the HQ). Note that removing a plugin only deletes its directory when it was installed by the management API — a hand-dropped or path-linked plugin is left on disk by design.Sub-agents
A sub-agent didn't start (cap reached)
A sub-agent didn't start (cap reached)
agent (or spawn_worker) call.This is a cap doing its job. The message tells you which one:too many workers running at once (max N) — wait for workers to finish— the agent’s concurrent limit.swarm run reached its worker limit (N workers per run)— the total-per-turn limit.the HQ is at its global worker limit (N) — wait for workers to finish— the HQ-wide ceiling across all agents.
subagents block if the work genuinely needs more — see Configuration → Sub-agents. The change takes effect on the agent’s next message. The HQ-wide ceiling (default 16) is raised by setting SUBAGENTS_MAX_CONCURRENT_GLOBAL where the HQ runs and restarting it — see Configuration → HQ defaults.Agent would be spawned with zero tools
Agent would be spawned with zero tools
mcp__… entries), or edit the type’s tools: frontmatter to ask for something the parent has. A sub-agent can never hold a tool or MCP server its parent lacks — see Configuration → Sub-agent types.depth limit reached
depth limit reached
subagents.maxDepth (default 3).Fix: raise maxDepth for that agent, or have the work done one level up. Note that an agent already at the ceiling is not given the agent tool at all, so in most cases it simply won’t try. Separately, chat shows one level of nesting: expanding a sub-agent shows its transcript, and a row inside that transcript reads “Nested agents this deep are not opened here.” — that is the display limit, not the run limit.alias "opus" is not configured (subagents.modelAliases)
alias "opus" is not configured (subagents.modelAliases)
agent tool’s model parameter accepts short alias names as well as full model ids. An alias is looked up in the agent’s subagents.modelAliases, and no aliases are configured by default — which model opus should mean depends on which provider the agent uses, so nothing is assumed. An alias that isn’t in the map resolves to nothing, the sub-agent runs on the parent’s model, and the note above is appended to the tool result. Nothing failed.Fix: add the alias to the agent’s subagents.modelAliases (for example {"opus": "anthropic/claude-opus-4-6"}), or pass a full provider/model id (or inherit) instead. Either way, if the id isn’t the parent’s model or one of its fallbacks, add it to the agent’s subagents.allowedModels first — see Configuration → Sub-agents.My sub-agent stopped waiting for an answer
My sub-agent stopped waiting for an answer
ask_orchestrator, showed as waiting for input, and then carried on — or finished — without anyone answering. Its own transcript shows the call coming back as ask_orchestrator aborted.A question lives only as long as the turn that launched the sub-agent. When that turn ends, any question still open is dropped so the sub-agent is not left waiting on a conversation that has moved on. A foreground sub-agent holds its parent’s turn open until it finishes, so there is time to answer from the reply box on its row. A background sub-agent usually outlives the turn that launched it, so a question it asks after that turn has ended has nobody to answer it.Fix: answer while the turn is still running, or launch the sub-agent in the foreground when you expect it to need a decision. A brief that tells the sub-agent what to assume when it cannot ask is the sturdier fix for background work.isolation: worktree requires a git workspace
isolation: worktree requires a git workspace
isolation: worktree gives a sub-agent its own checkout of the workspace, cut from whatever commit the workspace is on right now. That needs the workspace to be inside a git repository.Fix: run git init in the agent’s working directory (or point the agent at a directory that is already a repo), or drop isolation and let the sub-agent share the parent’s workspace.My sub-agent's worktree wasn't removed
My sub-agent's worktree wasn't removed
~/.dash/gateway/worktrees/<agent-name>/<subagent-id>/ after the sub-agent finished.This is by design when the worktree holds work. Cleanup removes a worktree only when there is nothing to lose: uncommitted changes, untracked files, and commits that no branch or tag would keep alive all keep it. (Regenerable litter — node_modules/, dist/, build/, .next/, coverage/, *.log, .DS_Store — does not count.) The path is not handed back to you in the chat: to find it, either fill in the template above with the sub-agent’s id, or look in the HQ log, where every kept worktree is recorded with a line containing keeping and the path, and why it was kept.Fix: look at what’s inside and keep or merge what you want. Once the checkout is clean, git worktree remove <path> from the parent repository takes it down; git refuses while there are changes in it, so commit or discard them first (or pass --force if you are sure).The HQ restarted while sub-agents were running
The HQ restarted while sub-agents were running
interrupted.Unlike earlier releases, an interrupted sub-agent is not lost: press Resume on its row — from the web tasks panel, the iOS tasks sheet, or POST /subagents/:id/resume; Desktop greys the button once a sub-agent is terminal — or have the parent send_message it, and it picks up with its context intact. Orphaned worktrees are swept at the same time, except ones holding work.Resume is refused or greyed out
Resume is refused or greyed out
send_message — comes back with an error instead. There are three common reasons, and a resume also counts against the launch caps, so the two cap messages described under “A sub-agent didn’t start (cap reached)” above can arrive here too:Agent "..." is a one-shot Explore agent and cannot be resumed.—ExploreandPlanare read-only, one-shot types, so they cannot be given a new task. Fix: launch a new one with the follow-up task. (If the agent is still running and asking a question, that is an answer, not a resume, and it goes through: the parent’ssend_message, the reply box on its row and the legacysend_to_workerall reach a paused one-shot.)steer cap reached for "..." (max 10 per agent).— you’ve hit the per-child message cap, which counts across resumes for as long as the HQ holds that child in memory (a restart resets it to zero). Fix: raiseswarm.maxSteersPerWorkerfor the agent, or start a fresh sub-agent.Agent "..." cannot be resumed: its grant cannot be rebuilt.— the parent’s grant could not be re-established. Either sub-agents have been turned off on the parent agent (or the agent itself was deleted — its conversations survive the delete, but nothing under them can run again), or the parent conversation (or one above it) was deleted — deleting a conversation stops everything under it from running again. A sub-agent created by an older HQ build, before the grant was stored beside the row, has the same symptom. Fix: re-enable sub-agents on the parent agent — see Configuration → Per-agent settings. A deleted parent, a deleted agent and a grant that was never stored cannot be recovered, so launch a new sub-agent instead.
POST /subagents/:id/resume to resume one from there.Where are the sub-agent transcripts?
Where are the sub-agent transcripts?
~/.dash/gateway/sessions/<agent-name>/.swarm/<runId>/; those directories are no longer written to and are left alone — remove them by hand if you want the space.No sub-agent progress on Telegram / WhatsApp
No sub-agent progress on Telegram / WhatsApp
An old conversation's cancelled worker lost its reason
An old conversation's cancelled worker lost its reason
cancelled without the explanatory note. Nothing else about the replay changed, and nothing needs fixing.Session issues
Provider session JSONL is corrupt
Provider session JSONL is corrupt
- Find the conversation’s session directory:
~/.dash/gateway/sessions/{agent-name}/{conversationId}/and open the.jsonlsession file inside it - Open it in a text editor
- Remove or fix the malformed line(s) — each line should be a valid JSON object
- Restart Dash
Starting with fresh provider context
Starting with fresh provider context
My data moved after updating
My data moved after updating
~/.dash (HQ data, desktop app data, logs, and agent workspaces). The first time a newer version starts, it automatically moves data from the old locations into ~/.dash — your credentials, agents, and conversations come along.If something looks missing, check the old locations:- macOS:
~/Library/Application Support/dashand~/Library/Application Support/dash-gateway - Linux:
~/.local/share/dashand~/.local/share/dash-gateway - Agent workspaces: the old
~/dash-workspaces
~/.dash doesn’t already have that data, and it never deletes the originals — so it’s always safe to copy anything left behind by hand. To pin Dash to a specific location instead, set DASH_HOME.Docker issues
Data lost on restart
Data lost on restart
DASH_HOME (set to /data in the container). Make sure that path is backed by a persistent volume in docker-compose.yml:Debug logging
Desktop and the HQ write logs to~/.dash/logs/ (mc.log and gateway.log) — check there first when something goes wrong.
For a standalone HQ, add the --verbose flag to get debug-level output: