claudex

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.

  1. Check ~/.claudex/server-stdout.log for the worker's last lines.
  2. Check ~/.claudex/logs/server.log for the failed boot.
  3. 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:

  1. HTTPS at the browser (any tunnel that terminates TLS).
  2. The page added to your home screen as a PWA (long-press → Add to Home Screen on iOS).
  3. 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
this wipes everything Sessions, queue, routines, push devices, transcripts — all gone. Back up ~/.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.