Skip to content

Troubleshooting

Sia edited this page Jun 2, 2026 · 5 revisions

Troubleshooting

Common issues and one-shot fixes.

Claude console: "Server is temporarily limiting requests · Rate limited" (HTTP 429)

This is not your plan's usage limit (the message explicitly says "not your usage limit"). Anthropic's infrastructure is throttling requests from your source because too many turns are in flight at once from the same account+IP.

Most common cause: firing prompts across several projects (and/or sub-agents, and/or prompt automation) at the same time. Each console is an independent claude child process hitting the API concurrently — that burst is what gets throttled. A second machine with a single session on the same account stays fine because it never bursts.

Fixes (in order of impact):

  1. Cap concurrent turns. /settings → Claude → Max concurrent turns (or claude.maxConcurrentTurns in server.yml, default 3). Excess turns queue instead of bursting, and the waiting console shows a "동시 작업 한도(N개)에 도달해 대기 중" notice — once another project's turn finishes, the queued one proceeds automatically, in order. Lower to 2 if you still see 429, especially on the 1M-context model. 0 = unlimited (old behaviour).
    • v1.90.0+ — applied immediately, no restart. Saving the value in /settings retunes the shared gate live (ClaudeConcurrencyGate.setLimit): raising lets queued turns start at once; lowering keeps in-flight turns and applies the new cap to new turns. The cap is shared across the main console, sub-agents and prompt automation (one account = one pool).
    # server.yml
    claude:
      maxConcurrentTurns: 3
  2. Serialize manually — wait for one project's turn to finish (busy badge clears) before firing the next.
  3. Reduce 1M-context usage — the 1M beta has tighter rate limits; switch heavy projects back to the standard context where 1M isn't needed.
  4. Update the CLI — newer Claude Code versions back off and retry on 429 instead of surfacing the error.

Note: 429 throttling is temporary; the CLI usually recovers on its own. The cap above simply stops you from self-inflicting it.

A /settings change doesn't seem to take effect

v1.90.0+ — saving /settings writes the external config/server.yml and updates the live config holder (ConfigHolder). The form reflects the saved value immediately, and values read at runtime — notably Max concurrent turns — apply at once (no restart).

Some values are bound at startup and still need a container restart: server host / port / name, database connection, workspace root, and anything injected into a long-lived component at boot. The form shows the new value right away, but the running behaviour changes only after docker compose up -d --force-recreate.

Before v1.90.0 the settings form re-rendered the startup snapshot, so a saved value looked unchanged until restart even though the file was written correctly. That display bug is fixed — if a value still doesn't apply after save, it's one of the startup-bound values above.

"Permission denied" on ./vibe-coder-data/

PUID / PGID in .env don't match the host user.

id -u; id -g                             # check host uid/gid
# update .env's PUID/PGID, then
docker compose up -d --force-recreate

If files were created with wrong ownership:

sudo chown -R $(id -u):$(id -g) vibe-coder-data/

Build fails: "SDK location not found"

vibe-doctor hasn't been run. From the web UI: Build environmentInstall/update all → wait 5-15 min. Or CLI:

docker exec -it vibe-coder-server vibe-doctor android

Claude says "Not logged in" but UI shows ✓

Two distinct fixes for the same symptom, depending on cause:

Fix 1 — root vs vibe credentials location

You ran docker exec -it vibe-coder-server claude login without --user vibe. docker exec defaults to root, so credentials went to /root/.claude/. The server (running as vibe) doesn't read that path.

# Re-login as vibe
docker exec -it --user vibe vibe-coder-server claude login

# Then verify
docker exec -it --user vibe vibe-coder-server claude auth status

Fix 2 — expired token

The .credentials.json exists but claudeAiOauth.expiresAt is in the past. The diagnostic detects this and shows "✗ Token expired".

# Re-login (refresh token will reactivate access)
docker exec -it --user vibe vibe-coder-server claude login

If refresh token is also expired (≥30 days unused), the full OAuth flow is required.

Slow builds

The Gradle dependency cache is empty on first build. Subsequent builds are 5-20× faster.

# Give Gradle more RAM if you have it
# In .env:
JAVA_OPTS=-Xmx8g -XX:+UseG1GC -Dfile.encoding=UTF-8
docker compose up -d --force-recreate

MCP install fails with "404 Not Found"

The MCP package name has changed upstream. The catalog's COMMUNITY / EXPERIMENTAL tier carries this risk. Workarounds:

# Find the new name on npm
docker exec -it --user vibe vibe-coder-server npm search <keyword>

# Install manually
docker exec -it --user vibe vibe-coder-server npm install -g <new-package-name>

# Edit .mcp.json by hand
docker exec -it --user vibe vibe-coder-server vi ~/.claude/.mcp.json

Open an issue to update the catalog.

Wireless ADB: device is discovered but "Connect" fails (failed to connect to <ip:port>)

The device shows up in auto-discovery, but clicking Connect returns failed to connect to '192.168.0.65:46377' (no Connection refused).

Cause: Android 11+ wireless debugging has two services — a one-time pairing service (_adb-tls-pairing, code-based) and a connect service (_adb-tls-connect). The connect service is advertised over mDNS even when this host is not paired yet, so it appears in the list with a Connect button — but an unpaired key is rejected at the TLS layer (the port is open, hence no Connection refused, just failed to connect).

Fix — pair once:

  1. Phone → Developer options → Wireless debugging → Pair device with pairing code. Note the IP:PAIRING_PORT (different from the connect port) and the 6-digit code.
  2. On the /adb page, use the Pair form (step ①) with that IP:port + code.
  3. After "Successfully paired", the server auto-connects to the discovered connect port. If discovery can't find it, press Connect with the IP:port from the wireless debugging main screen.

The adb key lives in ~/.android (persisted via the dev-tools/android volume), so pairing is a one-time step — it survives container restarts.

The server replaces the raw failed to connect with a "pair first" hint and auto-connects right after a successful pair.

git clone fails with 502 clone_failed exit 128

Authentication failure. Diagnose:

  1. Public repo? Try git clone <URL> from the host to confirm URL is correct.
  2. Private HTTPS? Did you register a PAT in /settings/git-integrations? The PAT's host must match the URL host exactly (github.com, not www.github.com).
  3. Private SSH? Did you ssh-keygen and register the public key in your provider? Check: docker exec -it --user vibe vibe-coder-server ssh -T git@github.com should reply Hi <username>!.

"Repository not found" cloning a wiki

GitHub wikis require the first page to be created via the web UI before the wiki repo (<repo>.wiki.git) exists. Same applies if you're trying to mirror a wiki to vibe-coder via clone.

WebSocket disconnects after 30 s of silence

Reverse proxy is timing out idle connections. Server sends a ping frame every 20 s, so any non-broken proxy keeps the connection alive. If you're behind nginx:

location /ws/ {
    proxy_pass http://upstream:17880;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 86400s;
    proxy_send_timeout 86400s;
}

Container won't start: "GID '1000' already exists"

You're using a base image where the default user has UID/GID 1000. The official image removes the default ubuntu user before adding vibe. If you see this on a custom image:

RUN userdel -r ubuntu 2>/dev/null || true && \
    groupdel ubuntu 2>/dev/null || true
# ...then groupadd/useradd vibe...

Image pull is slow

Use a registry mirror in your daemon config (/etc/docker/daemon.json):

{ "registry-mirrors": ["https://your-mirror.example.com"] }

Then restart Docker.

Debug: tail server logs

docker compose logs -f --tail=200 vibe-coder-server

Useful filters:

# Only WARN/ERROR
docker compose logs vibe-coder-server | grep -E '(WARN|ERROR)'

# Only HTTP requests
docker compose logs vibe-coder-server | grep -E 'GET|POST|PUT|DELETE'

Server log level: edit server/src/main/resources/logback.xml and rebuild (or pass -Dlogback.configurationFile=/path/to/your.xml).

Reset everything (nuclear option)

docker compose down
rm -rf vibe-coder-data/    # ⚠ deletes ALL state, including auth
docker compose pull
docker compose up -d
# Re-do /setup, re-install build environment, re-login Claude, re-clone projects

To preserve projects but reset the rest:

docker compose down
mv vibe-coder-data/workspace /tmp/keep-workspace
rm -rf vibe-coder-data/
mkdir -p vibe-coder-data
mv /tmp/keep-workspace vibe-coder-data/workspace
docker compose up -d

Clone this wiki locally