Troubleshooting
Boot issues, restart hangs, HTTP gotchas, and what to look at first.
"Server won't start"
Port 5179 already in use
lsof -ti :5179 -sTCP:LISTEN
If a stale claudex (or anything else) holds the port, kill it. The bundled
scripts/restart.mjs waits for the port to drain before relaunching, so a clean kill is enough.
"refusing to bind to 0.0.0.0"
By design. claudex only binds to 127.0.0.1 / ::1 / localhost. To reach it
from another device, see Remote access. There is no flag to override this — public
exposure is your tunnel's responsibility.
"db is locked" / migration fails
SQLite uses WAL mode by default. If a stale process holds the WAL, a fresh boot can stumble. Stop all claudex processes and try again:
pgrep -af claudex
# kill anything that shows up, then
pnpm serve "Login works on desktop but not on phone"
Mixed content
If the page is loaded over HTTPS but the WebSocket URL is ws://, the browser blocks the connection.
Front claudex with a tunnel that terminates TLS so both the page and the WS land on the same scheme.
Cookie blocked
The auth cookie is SameSite=Lax, Secure when served over HTTPS. Some Safari versions on
iOS won't keep the cookie if the host is an IP literal — use a hostname (Tailscale's *.ts.net, your own
domain, or a LAN .local mDNS name) and the cookie sticks.
Behind Cloudflare with WebSocket disabled
Some Cloudflare zone settings disable WebSocket by default for non-Pro plans. Open the zone settings → Network → WebSockets and turn it on. Without it the connection drops to polling and chat silently freezes.
"Restart says success but the server is gone"
The bundled restart helper (scripts/restart.mjs) spawns a detached worker that polls for the port to
free up, then re-execs the server. If the worker dies before the new server boots, the port stays free and the
restart silently no-ops.
- Check
~/.claudex/server-stdout.logfor the worker's last lines. - Check
~/.claudex/logs/server.logfor the failed boot. - Restart manually:
pnpm serve.
"WebSocket disconnects every few minutes"
Cloudflare Tunnel and some shared frps setups idle out long-lived connections. claudex pings every 25s by default. If your front-end idle limit is shorter, reduce it on the tunnel side or — for a quick fix — leave the tab focused. The browser will auto-reconnect.
"Permission prompts never arrive on my phone"
Push notifications require a secure context. Over plain HTTP they silently degrade to in-tab alerts only — open the app, the alert is there. If you want true OS-level pushes, you need:
- HTTPS at the browser (any tunnel that terminates TLS).
- The page added to your home screen as a PWA (long-press → Add to Home Screen on iOS).
- Notifications allowed for the page in browser settings.
"It worked yesterday and now nothing works"
Run the diagnostic snapshot — it never starts the server, never takes a write lock:
pnpm claudex:status Output covers the running/stopped state, DB size, migration count, session totals, queue counts, push-device count, and (best-effort) the frpc PID. It's the fastest way to spot "the server died and I missed it" vs "the DB is wedged" vs "the tunnel is the problem."
Resetting credentials
If you've forgotten your password but your TOTP still works, reset just the password:
pnpm reset-credentials --username=you --password='new-pw' The TOTP secret stays untouched, so your authenticator entry keeps working.
If you've lost both your password and your TOTP, your only path back is to delete the DB and re-init:
rm ~/.claudex/db.sqlite
pnpm run init ~/.claudex/ first if any of that matters.
Still stuck?
Open an issue at github.com/ahaostudy/claudex
with the output of pnpm claudex:status and the last 100 lines of
~/.claudex/logs/server.log. Redact anything sensitive — claudex doesn't try to scrub logs for you.