troubleshooting
Troubleshooting.
Every Shoti error ends in a help link. Here is the fix for each, by area. Run shoti explain <topic> to read any of them offline.
auth
- Couldn't read your credentials — Shoti found ~/.shoti/auth.toml but couldn't read or parse it.
- OAuth provider required — A sign-in request reached the API without a provider.
- Redirect URL not allowed — The sign-in redirect URL's host isn't in the server's allowlist.
- Sign-in required —
shoti doctorfound no credentials at ~/.shoti/auth.toml. - Couldn't save your credentials — Sign-in succeeded, but writing ~/.shoti/auth.toml failed.
- Sign-out couldn't clear credentials — Sign-out couldn't remove ~/.shoti/auth.toml.
- Browser sign-in can't reach the app — Finishing sign-in in the browser didn't return you to the desktop app. The
shoti://link the browser hands back to isn't registered with your operating system. - Couldn't open a local sign-in port —
shoti logincouldn't bind a localhost port to receive the browser's sign-in callback. - Login state mismatch — The login callback's state parameter didn't match — a stale browser tab, or a possible CSRF attempt.
- Login timed out —
shoti loginwaited five minutes for the browser callback and gave up. - Sign-in code exchange failed — The browser sign-in finished, but exchanging the callback code for tokens failed.
- You're not signed in — A command needed Shoti credentials, but none were found at ~/.shoti/auth.toml.
- Session token expired — Your access token expired.
shoti doctor/shoti_statusmay still report "signed in" from local files, but authenticated calls now return 401 until the token is refreshed. The agent daemon normally rotates it automatically; if the daemon isn't running, the token stays stale. - Session expired — Your Shoti session expired and the agent daemon couldn't refresh it after more than seven days.
team
- Team name already taken — You already own a team with that name.
- Multiple teams, none active — You belong to more than one team, so
shoti initcan't pick one for you. - Team name required —
shoti initneeds a team name and none was given. - Role too low for that action — Your role on this team isn't high enough for what you tried to do.
- No valid invite emails — No valid email addresses remained after filtering the
shoti team invitearguments. - No active team selected — You're signed in, but no active team is set.
- The machine id is not a valid UUID — A presence update sent a machine_id the API could not parse as a UUID, so the device's here-now row was refused.
- You're not a member of that team — Shoti tried to show or update your device's presence on a team you don't belong to, so the server refused it.
- The presence patch was empty — A PATCH to the presence endpoint carried neither display_name nor hidden, so there was nothing to change.
- This repo is not linked to your team — Shoti installs into your agent for every project on this machine, so a repo sends to your team only after you link it. Nothing from an unlinked repo leaves your machine, and each withheld send is recorded with a reason.
- Team selector matches more than one team —
shoti team usegot a prefix that matches more than one of your teams. - Can't remove the last owner — A team must keep at least one owner, and this would remove the last one.
- Not a valid team id —
shoti team use <id> --idgot an argument that isn't a team UUID. The --id flag (used by the desktop switcher) takes an exact team id and skips the network lookup, so it must be a real UUID. - Only owners can invite owners — You tried to send an owner-role invite, but only owners can do that.
- Invalid invite email — One or more of the invite addresses aren't valid emails.
- Invalid invite role — The invite role must be owner, admin, or member.
- Too many invites at once — That request had more invites than one call allows.
- User isn't on that team — The user you tried to act on isn't a member of that team.
- Team name too long — Team names are capped at 100 characters.
- Not a member of that team — You're not a member of the team you tried to act on.
- Team not found — The team id in the request doesn't match any team you can see.
- Couldn't finish joining — The desktop welcome step couldn't finish setting up your membership — usually a dropped connection mid-request.
broadcast
- Broadcast intent required —
shoti broadcastwas called with no intent. - Catch acknowledgement needs a numeric id — shoti_catch_ack was called without the integer catch id from the catch heads-up.
- This shoti build is too old to send from a repository — The API refused a repository-scoped message because this shoti build predates repository linking (v0.5.5). Newer builds only send from repos you have linked; an older build has no such gate, so the server holds that line for it. Letters, replies, and work without a checkout still send.
- Consolidation diff too large for one request — The world-map consolidation worker tried to submit a structural diff over the per-request size budget. The whole diff must fit one atomic request (the compare-and-swap on base_cursor can't span POSTs), so it can't be chunked like a seed batch.
- Broadcast not found — No broadcast with that event id exists on this team.
- Broadcast intent too long — Broadcast intent is capped at 4096 characters.
- Malformed idempotency key — The idempotency key must be 8-64 characters from [A-Za-z0-9_-].
- Broadcast needs an intent — A broadcast reached the API with no intent.
- Not a member of the active team — Your active team points at a team this account does not belong to, so the API refuses every broadcast to it. The message is accepted on your machine and then discarded, which is why nothing you send ever appears.
- Only the author can recall — Only the broadcast's original author can recall it.
- Invalid decision type —
shoti broadcast --typegot a value that isn't a known decision type. - Couldn't locate ~/.shoti — Shoti couldn't find or create the ~/.shoti directory.
- Couldn't queue your message — A broadcast or response couldn't be written to the local queue at ~/.shoti/queue.
- Recall needs an event id —
shoti recallneeds the event id of the broadcast to pull back. - Reply text required —
shoti respondgot an event id but no message. - Respond needs an event id —
shoti respondneeds the event id of the broadcast you're replying to. - Couldn't read the piped intent —
shoti broadcast -was told to read the intent from stdin, but the read failed.
agent
- Agent daemon stopped —
shoti doctorfound the agent daemon stopped. - Agent daemon not running — The background agent daemon isn't running, or its socket is unreachable.
- Agent pairing code rejected — The agent pairing code was rejected — it may have expired (15-minute TTL), already been used, or the owner denied the request.
- Agent lost its own binary — The agent couldn't resolve its own executable path — this happens when the binary moves mid-run.
- Couldn't start the agent daemon — Shoti couldn't spawn the background agent daemon.
- Couldn't report a fleet task result — shoti_report_result couldn't send your runtime's output back to the fleet task — the task may have expired, the session may have stopped, or the call hit a transient network error.
- That device isn't yours to change — Renaming or hiding a device requires a machine id you own; the one in the request matched no device on your account.
build
- Couldn't write the build brief —
shoti buildresolved the place, but couldn't write the temporary scoped brief file that Claude Code reads at startup. - Claude Code isn't on your PATH —
shoti buildhands the scoped place off to a local Claude Code session, but theclaudecommand wasn't found on your PATH. - That runtime can't accept a scoped brief directly — The chosen runtime has no way to receive a brief as an argument, so
shoti buildprinted the brief and the exact command to start it yourself instead of launching it. - No agent runtime found —
shoti buildlooked for claude, cursor, and codex on your PATH and found none. - Run
shoti buildinside your repo —shoti buildresolves a place to the code it owns, so it must run from inside the git repository the place is bound to — but the current directory is not a git repo. - --packet isn't valid JSON —
shoti build --intent --packetwas given a --packet value that failed to parse as JSON. - That place isn't on the work-map —
shoti buildwas given a place id that isn't in your team's work-map — it may be mistyped, from another team, or the map hasn't been seeded yet. - Place is bound to a different repo — The place you asked to build from is bound to a different repository than the one you're standing in, so its file scope wouldn't line up with your working tree.
- Multiple runtimes installed, none set as the default — More than one supported agent runtime is on your PATH and shoti has no remembered default, so it can't pick silently in a non-interactive shell.
- That runtime isn't installed — The chosen runtime (from --runtime, the remembered config.toml key, or the interactive pick) wasn't found on your PATH.
- Not a runtime shoti knows —
--runtimeor the rememberedruntimekey in config.toml named a value that isn't one of shoti's supported agent runtimes. - Name a session to dispatch to —
shoti fleet buildhands a place to one of your own live fleet sessions on another machine, so it needs a target session — but no--to <session-id>was given. - A runtime is installed but not wired — shoti doctor found an agent runtime (Cursor or Codex) on this machine whose shoti wiring is missing or stale — its sessions can't broadcast or hear the team until it's wired.
- No indexable source found — The cold-start seed indexed the chosen repo but found no source files in a language it parses (Go, TypeScript, TSX, or JavaScript), so there's nothing to turn into a map yet.
- Conflicting seed flags — shoti-seed was run with --rename and --name-new-only together. A rename pass targets exactly the already-persisted places that --name-new-only excludes, so the combination would spend naming quota and then skip the rename preview it was asked for.
- Choose a folder that's a git checkout — The cold-start seed turns a repo into your team's first map, so the chosen folder must be a git checkout — but it isn't one.
- That folder is a different repo — The map heard work in one repo, but the folder you picked derives to a different repo key. Adding it under the heard repo would bind the wrong code to the wrong places.
- The server rejected the seed — The cold-start seed reached api.shoti.ai, but the server rejected the places or bindings it tried to persist.
config
- Config value can't be empty —
shoti config set display-namewas given an empty value. - Invalid telemetry value —
shoti config set telemetrygot a value that isn't off, anonymous, or full. - Unknown config key —
shoti config setgot a key it doesn't recognize.
setup
- Aider isn't wired in v1 —
shoti install-hooksdetects Aider but does not configure it, so Aider sessions cannot use Shoti through the supported setup path. - Sync hooks into Conductor — Hooks were written, but Conductor mirrors agent configs through its own settings.
- Cursor rule skipped — not in a project directory —
shoti install-hookswired Cursor's mcp.json and hooks.json but skipped writing .cursor/rules/shoti.mdc because the working directory has no .git or .cursor directory. - Desktop update didn't finish — Shoti couldn't finish checking for or downloading a desktop update. The version you're running keeps working.
- --local requires --json —
shoti doctor --localwas run without--json. The--localflag only controls the machine-state JSON probe consumed by the desktop — it has no effect in the human-readable or--cidoctor path. - Unknown installer option — The installer was passed a flag it doesn't recognize.
- Install download failed — The installer couldn't download the shoti binary or its checksums from dl.shoti.ai.
- Couldn't locate the shoti binary —
shoti install-hookscouldn't resolve the path of its own binary to wire into the hooks. - Couldn't update a Claude Code config file — Shoti couldn't write its changes to a Claude Code config file under ~/.claude/.
- Unsafe binary path for hooks — Shoti refused to wire its hooks because the binary's path contains a shell metacharacter.
- curl is required to install — The installer needs curl (or GNU wget) to download over TLS; BusyBox wget can't enforce a secure transport.
- CLI distribution isn't live yet — The installer couldn't reach the Shoti CLI release channel — the download host may not be serving yet.
- Couldn't create a temp directory — The installer couldn't create a temporary working directory to download into.
- Install path has shell metacharacters — The chosen install directory contains characters (double-quote, backtick, $, %) that aren't safe to embed in the agent hook commands shoti writes.
- Unsupported platform — The installer doesn't ship a prebuilt binary for this operating system or CPU architecture.
- Couldn't verify the download — The installer couldn't verify the download's checksum or signature, or a required tool (minisign / sha256sum) was missing.
- No map root set for this machine — The map-simplification one-root registry (~/.shoti/root.json) has no directory registered for this team —
shoti root scanandshoti doctorhave nothing to walk. - No agent runtimes detected —
shoti install-hooksfound no agent runtimes to wire into. - Couldn't delete ~/.shoti —
shoti uninstallremoved the Claude Code wiring but couldn't delete the ~/.shoti/ directory. - Couldn't remove the hooks —
shoti uninstallcouldn't remove Shoti's hook entries from ~/.claude/settings.json. - Couldn't remove the MCP entry —
shoti uninstallcouldn't remove Shoti's MCP server entry from ~/.claude/settings.json. - Update failed its checksum — The binary
shoti upgradedownloaded did not match its published SHA-256 — a corrupted or tampered download. - Refusing to downgrade — The version
shoti upgraderesolved is the same as or older than the one you're running. - Couldn't fetch the update —
shoti upgradecould not download the release manifest or the new binary from dl.shoti.ai. - shoti is managed by a package manager —
shoti upgradedetected that this shoti was installed by a package manager (Homebrew, Scoop, Chocolatey, snap, apt), which owns the binary's files. - Can't replace the shoti binary —
shoti upgradecould not write over the installed binary — its directory isn't writable by you (e.g. a root-owned /usr/local/bin). - Update failed its signature —
shoti upgradecould not verify the minisign signature on the release — the update could not be authenticated. - Windows SmartScreen blocked the installer — Running the Shoti installer on Windows showed "Windows protected your PC." The beta installer isn't code-signed yet, so Microsoft Defender SmartScreen warns before anything new and unsigned runs.
- Update couldn't be installed — The desktop app downloaded an update, but installing it failed. The version you were running keeps running — nothing is lost.
demo
- Demo couldn't start —
shoti democouldn't set up its throwaway session directory. - Desktop demo can't find the app —
shoti demo --desktopcan't find the desktop app (thedesktop/folder) from the current directory. - That desktop/ folder isn't the Shoti app —
shoti demo --desktopfound adesktop/folder up the tree but itssrc-tauri/tauri.conf.jsonisn't Shoti's (the bundle identifier doesn't match), so it refused to runpnpm tauri devthere — running an unverified package's scripts could execute untrusted code. - Desktop demo needs pnpm —
shoti demo --desktopneeds pnpm and it isn't on your PATH. - Vignette unavailable with --desktop —
--vignetteisn't available with--desktop, which only runs the demo-hero story. - Demo couldn't set its environment —
shoti democouldn't set the environment variables that keep the demo offline and sandboxed. - Demo is offline by design — A network call was attempted from inside
shoti demo, which is offline by construction so it can never publish to a real team. - Invalid demo seed —
shoti demo --seedgot a value that isn't an integer. - Unknown demo vignette —
shoti demo --vignette(or SHOTI_DEMO_VIGNETTE) named a script that doesn't exist.
network
- Can't reach the API — Shoti couldn't reach api.shoti.ai.
- Request timed out — The server took too long to respond during sign-in or setup.
- Network unreachable — Shoti couldn't reach api.shoti.ai over the network.
- Rate limited — The Shoti API is rate-limiting your requests.
- Couldn't reach the API to seed the map — The cold-start seed indexed your repo locally, but couldn't reach api.shoti.ai to persist the map.
billing
- Writes disabled for this team — Your team's entitlement state (trial ended, past due, or archived) blocks new writes.
- Seat limit reached — Adding this teammate would exceed your team's seat limit.
- Trial ended — Your team's trial has ended.
internal
- Wrong arguments — A
shoticommand got the wrong number of arguments. - Shoti config file can't be read — config.toml exists but couldn't be opened or parsed — a permission problem or a corrupt file, not a missing setup.
- Unregistered error code — An error surfaced with a code that isn't registered in Shoti's error catalog — an internal consistency check.
- The event tail is polling instead of waking —
DATABASE_URL_DIRECTis unset, so the API can't hold the LISTEN session that turns Postgres notifications into long-poll wakeups. Nothing is lost — every connected client just re-queries once per second instead of waking the moment an event lands. - Old
shoti initform —shoti initwas given a repository URL argument — the old v0.2 form. Shoti now hosts everything for you. - Migration needs the direct URL — A database migration step needs the direct (non-pooled) connection URL. This is an operator topic, not a user error.
- Migration failed — A database migration failed to apply. This is an operator topic, not a user error.
- Shoti isn't set up here —
shoti doctorfound no Shoti configuration. - Test ping was skipped — The desktop test-ping couldn't record its liveness marker because another shoti process held the liveness write lock past the budget, so the write was skipped rather than blocking. Nothing was recorded — this is not a failure of your setup.
- Unknown ping source —
shoti ping --sourcegot a value that isn't a known agent. This is an internal test-ping the desktop uses to verify the liveness pipe. - The retention drain has no database — The retention drain was started without DATABASE_URL, so it cannot reach Postgres.
- Workmap corpus exceeds its measured budget — The slow-clock workmap pass found more exact-deduped intents than its measured clustering ceiling and refused before embedding or writing a partial map.
- Workmap encountered a foreign scope — The workmap seal contained a repo_key other than work:intents, so the worker refused instead of overwriting a map it does not own.
- Workmap feed exceeds its page budget — The slow-clock workmap pass reached its feed-page ceiling while the API still reported more events, so it refused to build from a truncated history.
- Couldn't write the workmap pass report — mapworker -workmap finished its pass but the JSON report file could not be written at the given path.
Still stuck? hello@shoti.ai. Back to shoti.ai.