Troubleshooting
When something won’t connect.
Every way a connection, tunnel or agent chat can fail, what causes it, and how to fix it. Find the symptom that matches what you’re seeing.
How it connects
CodeMote runs phone to computer over an encrypted WebSocket. Nothing is stored in our cloud; the link goes through a tunnel you control.
Your computer
The CodeMote VS Code extension, or the codemote CLI. It opens a local server and exposes it through a tunnel.
Public URL
Cloudflare by default. The host prints an https://… URL; the app connects to its wss://… form.
Your phone
Scans the QR the host shows, connects to that tunnel URL, and drives your machine.
- The host is running. VS Code open with CodeMote started, or
codemote startrunning in a terminal. Close it and the connection drops. - The tunnel is up and public. The host prints an
https://…URL; the app connects to itswss://…form. - The pairing code is fresh.Codes are single-use. A code that’s already been redeemed or expired is rejected, so show a new QR.
Connection & pairing
The common errors when scanning a QR or reconnecting, matched to the exact message CodeMote shows you.
“That doesn't look like a CodeMote pairing code.”
You scanned or pasted something that isn’t a CodeMote code: a different QR, a truncated copy-paste, or a screenshot that didn’t decode.
Fix. Scan the QR shown by CodeMote on your computer. Typing it by hand? Use Enter code manually and paste the entire pairing string exactly as VS Code or the CLI shows it.
“Pairing code already used or invalid. Show a fresh QR.”
Pairing codes are single-use. This appears if you scan the same code twice, or the code expired.
Fix. Generate a fresh QR on the host and scan again. Re-scanning a machine you’ve already paired is fine; the app reuses your saved session instead of the one-time code.
“The desktop rejected pairing (HTTP …).”
The desktop rejected pairing (HTTP …). Another CodeMote host may be sharing this tunnel; stop the extra one and rescan.
Your pairing request reached a backend that isn’t the host that created the code, almost always two CodeMote hosts running for the same workspace, splitting the tunnel between them. (Older builds showed this as the cryptic error 0.)
Fix. Make sure only one host is running for that project: close the duplicate VS Code window or stop the extra codemote start, then scan a fresh QR. See Two hosts, one workspace.
“Couldn't reach the desktop: …”
The app couldn’t open the socket to the tunnel URL. Usually the host isn’t running anymore, the tunnel is down or expired, the URL changed since you paired (Cloudflare rotates it on every restart, see Cloudflare), or the phone hit a network wall: captive Wi-Fi, VPN, airplane mode.
Fix. Confirm the host is up and showing a URL, check your provider section, and if the URL rotated, re-pair by scanning the new QR.
“Waiting to connect” never finishes
The tunnel is likely stopped, or set to Private rather than anonymous, so the handshake never reaches the host.
Fix. On the host, confirm the tunnel is running and its port is public. With the default Cloudflare provider this is automatic. With devtunnel the port must allow anonymous access; with the VS Code Ports panel it must be forwarded and set to Public. Then retry.
“It connected once but won't reconnect”
The host tunnel went away: computer slept, VS Code closed, or codemote startstopped. The app keeps the old URL and can’t reach it.
Fix. Bring the host back up so the tunnel is live again. CodeMote auto-reconnects to your last workspace once the host is reachable. If the URL changed (Cloudflare), re-pair.
“It keeps disconnecting”
A flaky network, or the host sleeping, drops the socket. CodeMote reconnects automatically with backoff when the host and tunnel come back; you’ll see Reconnecting to ….
Fix. Keep the host awake for long sessions. On a laptop, plug in and disable sleep, or switch to a stable provider so a brief drop doesn’t rotate the URL.
“Session expired. Please pair again.”
Your saved session token is no longer valid on the host, which restarted with new state or had the token revoked.
Fix. Re-pair by scanning a fresh QR.
“No saved session for <workspace>. Pair again.”
The app has that machine in its list but no valid saved credential for it, for example after the keychain was cleared.
Fix. Pair the machine again from the host’s QR.
“Update the app: protocol version mismatch.”
The phone app and the host are on incompatible protocol versions.
Fix. Update both the CodeMote app (App Store) and the host: the VS Code extension, or npm i -g codemote-cli@latest.
“I switched accounts and the tunnel URL stopped working.”
This is devtunnel-specific. A dev tunnel ID belongs to a single Microsoft account, so signing devtunnel into a different account changes the URL your phone was paired to.
Fix. Sign devtunnel back into the original account, or re-pair with the new URL. If repeated logins are the problem, switch to a set-once provider: ngrok or Tailscale.
Tunnel providers
Cloudflare is the default: zero setup, but a temporary URL. The others need one-time setup and give you a stable URL that survives restarts, so your phone never has to re-pair.
| Provider | Setup | URL | Best for |
|---|---|---|---|
| Cloudflare (default) | None, auto-downloads | Temporary, changes every restart | Trying CodeMote instantly |
| ngrok | Free account + one API key | Stable, *.ngrok-free.app | Setting it once |
| Tailscale | Install + tailscale up + Funnel | Stable, *.ts.net | Maximum privacy (your tailnet) |
| devtunnel | Install CLI + devtunnel user login | Stable, login can expire | Microsoft-stack users |
Switching providers
From the CLI, pass a flag to codemote start. Your choice is remembered, so a later codemote start reuses it.
codemote start # Cloudflare (default) codemote start --ngrok codemote start --tailscale codemote start --devtunnel
From VS Code, run CodeMote: Change Connection Method in the Command Palette, or tap Change provider on the pairing page. The provider pill there tells you which is active and whether the URL is temporary or stable.
Cloudflare
The fastest way to connect. On first use CodeMote downloads Cloudflare’s cloudflared binary for you and opens a temporary public HTTPS tunnel. No account, no login, no configuration.
The trade-off is that the URL is temporary. Every start gives a new random https://<words>.trycloudflare.com. When you stop, that URL is gone: your phone re-pairs next time, and terminal tabs tied to the old URL don’t carry over. The app warns you with a Temporary URL pill and a one-time prompt to set up a stable connection.
Cloudflare isn't installing automatically
CodeMote auto-downloads a pinned, checksum-verified cloudflared on first run, cached in ~/.codemote/bin/. If that download fails you’ll see a Could not obtain cloudflared error, a download HTTP <status> or redirect error, or a checksum mismatch. The cause is almost always a locked-down or corporate network, an offline machine, or a proxy that blocks github.com/cloudflare/cloudflared/releases.
Fix. Install cloudflared manually so it’s on your PATH; CodeMote uses the system binary instead of downloading. On macOS: brew install cloudflared (other platforms), then codemote start again. Or switch to a stable provider you install yourself: ngrok or Tailscale.
The tunnel URL never appears, or you're rate-limited
Timed out waiting for the Cloudflare tunnel URL or cloudflared exited before printing a URL means cloudflared started but never produced a URL, usually a transient Cloudflare outage or a blocked outbound connection. trycloudflare is best-effort and not meant for heavy use.
Fix. Retry. If it persists, or you’re hitting rate limits, switch to a stable provider.
devtunnel
Microsoft Dev Tunnels. Install the CLI (aka.ms/devtunnels/download), sign in with devtunnel user login, then start with codemote start --devtunnel. CodeMote creates the tunnel with anonymous access so your phone can reach it, and the URL is persistent.
devtunnel host exits before printing a URL
devtunnel host exited before printing a URL (code …). This usually means your dev tunnel session has expired: try running `devtunnel login` again, then retry.
The login session expired.
Fix. Run devtunnel user login again, then codemote start --devtunnel.
ngrok
A stable public HTTPS URL through your own free ngrok account. Create one at ngrok.com, make a key under Identity & Access → API Keys, and give it to CodeMote once.
codemote config set ngrok.apiKey <YOUR_API_KEY> codemote start --ngrok
From that one key CodeMote downloads the ngrok binary, mints an authtoken, and reserves your free static domain (a name ngrok picks, like curious-lion-1234.ngrok-free.app), then reuses that same URL every run. Scan the QR once; restarts don’t need a re-scan.
API key rejected, download fails, or the session won't start
ngrok API … failed (HTTP 401) means the key was mistyped or revoked; recreate it and re-run codemote config set ngrok.apiKey <key>. Could not download ngrok means your network blocked the download; install ngrok manually (ngrok.com/download) onto your PATH. ngrok exited before printing a URL usually means another ngrok agent is already running (the free plan allows one session); stop it and retry.
Fix. After fixing the underlying key or network issue, re-run codemote start --ngrok. It’s idempotent, so the one-time authtoken and domain setup finishes on the next run.
Tailscale
The most private option: the tunnel stays inside your own tailnet, and Tailscale Funnel exposes just the one port over a stable *.ts.net URL. Install Tailscale (tailscale.com/download), sign in with tailscale up, then enable Funnel in the admin console: turn on MagicDNS and HTTPS certificates under DNS, and add the Funnel node attribute under Access controls.
"nodeAttrs": [
{ "target": ["autogroup:member"], "attr": ["funnel"] }
]Then start with codemote start --tailscale. The URL is stable across restarts, so no re-scan is needed.
Not installed, not logged in, or Funnel unavailable
tailscale not installed means install it and re-run. not logged in means run tailscale up and finish the browser login. Funnel not available or Funnel is not enabled on your tailnet means the HTTPS certs or the funnelnode attribute aren’t enabled yet; complete the admin-console step above, which can take a minute to propagate.
Fix. If the URL still times out, verify tailscale funnel status works standalone, then retry.
Two hosts, one workspace
CodeMote maps each project to a deterministic port and tunnel. Start a second host for the same workspace and both fight over the same tunnel, which quietly breaks pairing.
Two VS Code windows on the same folder, or the extension and codemote start together, both try to own the same tunnel. CodeMote refuses the second host loudly instead:
CodeMote is already hosting this workspace on port …. Connect to that session, or stop it first, instead of starting a second host. Two hosts for one workspace share the same tunnel and break pairing.
Fix. Use the host that’s already running, or stop it before starting another. If a different program is squatting the port, you’ll instead see a warning that CodeMote fell back to a temporary port, and the tunnel URL differs until that port is free.
Agent chat
The Agent tab is gated by two things the host reports on connect: whether it can run agents at all, and whether Claude Code is installed on it.
“Claude agent needs the CLI” on the VS Code extension
Claude agent needs the CLI. You’re connected through the VS Code extension, which can’t run the Claude agent. Install the CodeMote CLI, then start your session from there.
The VS Code extension host can’t run agent chats, only terminals, editor, git and files. The “+” button is disabled on that connection.
Fix. Run the agent from the codemote CLI instead, then scan the QR from that session. Everything else keeps working on either host.
npm i -g codemote-cli codemote start
“Only Claude chats for now” on a CLI host
Only Claude chats for now. CodeMote runs Claude natively, and we couldn’t find Claude Code on this machine to start one.
You’re on a CLI host that can run agents, but CodeMote couldn’t find the claude executable. It checks your PATH, plus the two spots the installers use even when they’re not on PATH: ~/.local/bin/claude and ~/.claude/local/claude.
Fix. Install Claude Code (claude.ai/code), confirm claude --version runs in a terminal, then restart codemote start. If claudeworks in your normal shell but CodeMote can’t see it, you started codemote from an environment with a different PATH (a systemd unit or bare node); start it from your normal login shell instead.
The “+” button is greyed out
Same root cause: the host can’t run agents (extension host), or a chat is already starting. On a CLI host with Claude installed, “+” opens the persona picker to start a new chat.
Terminals & editor
Everything runs on the host, so most surprises here are the good kind: your work keeps going while the phone is away.
My terminal stopped updating, or output is frozen
Backgrounding the app tears down the live connection. Reopen CodeMote; it reconnects and replays the terminal so you’re caught up. Long-running commands keep running on the host while you’re away.
A command kept running after I closed the app
Expected. Terminals live on the host, so jobs keep going and are still there when you return.
I can't edit a file, or my edit didn't save
Make sure you’re connected and editing the Sourceview, not a rendered preview. Use the Rendered / Source toggle to switch back to editable source. If you see “This file changed on the desktop since you opened it,” the file was modified on the host, so reopen it to get the latest.
I'm not getting notifications
The agent waiting banner only fires when CodeMote is not the app on screen. Go to the Home screen, switch apps, or lock the device. Pulling Notification Center down over CodeMote still counts as foreground, so no banner shows there. Also confirm notifications are enabled for CodeMote in the iOS Settings app.
Git actions fail
Git runs on the host, so a failure usually means the host’s git would fail too: nothing to commit, no upstream, or credentials set up on the computer. Read the message and resolve it on the host. No GitHub sign-in happens on the phone, and no credentials are stored there.
Still stuck
Reach out and I'll help you get connected. It speeds things up to include your provider, whether the host is the VS Code extension or the codemote CLI, the exact error text, and what the host printed when it started.
Drive your AI agents, terminals and Git from your phone, with no cloud copy of your code.