Skip to main content

Troubleshooting

Solutions for common Remi issues.

Startup Issues

"No identity found"

No identity found. Run "remi keygen" first.

This is rare, because Remi generates an identity for you rather than requiring one up front. The daemon only touches an identity at all when authentication is enabled (remi --auth), and both the daemon and the client auto-generate a keypair when none exists, logging Generating new Ed25519 keypair... as they do.

Seeing this message means generation was attempted and the key still could not be read back, which almost always means ~/.remi is not writable or the identity file is corrupt. Check permissions first:

ls -la ~/.remi

Then generate explicitly, which will report the real error:

remi keygen

"Identity file is empty"

Identity file is empty. Run "remi keygen --force" to regenerate.

The identity file at ~/.remi/identity.json exists but is empty or corrupted. Regenerate it:

remi keygen --force

"Identity is encrypted and REMI_PASSPHRASE is not set"

Identity is encrypted and REMI_PASSPHRASE is not set.
Set REMI_PASSPHRASE or use an unencrypted identity.

Your identity was created with remi keygen --passphrase and is encrypted. You have three options:

  • Set the passphrase: export REMI_PASSPHRASE="your-passphrase" then retry
  • Remove the passphrase: remi keygen --decrypt (keeps the same keypair; no re-authorization needed)
  • Regenerate unencrypted: remi keygen --force (creates a new keypair; clients must re-authorize)

"Failed to unlock identity"

Failed to unlock identity: ...
Wrong passphrase?

The passphrase provided does not decrypt the identity file. If you forgot the passphrase, generate a new identity with remi keygen --force and re-authorize all clients.

Connection Issues

"Cannot connect to daemon"

The Remi web app cannot reach the WebSocket server.

Possible causes:

  • Remi is not running. Start it with remi my-project or remi --daemon.
  • Wrong port. Check if you customized the port with --port or REMI_PORT.
  • If you started with --local or --bind localhost, the daemon only accepts connections from the same machine. Use the default bind (0.0.0.0) to accept connections from other devices.
  • Firewall blocking the port. Ensure port 18765 (or your custom port) is accessible.
  • Wrong IP address. Verify the server's IP with hostname -I (Linux) or ipconfig getifaddr en0 (macOS).
  • In wrapper mode, the WebSocket server may have silently failed to start. Check ~/.remi/remi.log for startup errors.

"Connection timeout"

The WebSocket connected but the handshake did not complete within 10 seconds.

Possible causes:

  • The server is under heavy load or unresponsive.
  • Network latency is too high for the timeout. Try a direct connection instead of relay.
  • The server does not recognize the protocol version.

Port Already in Use

EADDRINUSE: port 18765 already in use

Another process is using the port. Either stop that process or use a different port:

remi --port 9001 my-project

In wrapper mode, port conflicts are logged to ~/.remi/remi.log silently and Claude continues normally.

Authentication Issues

"AUTH_REQUIRED" / "UNKNOWN_KEY"

The server requires authentication but does not recognize the client's public key.

Solution: Authorize the client's key on the server:

remi authorize client-key.json --label "Device Name"

See the Authentication Guide for full setup instructions.

"INVALID_SIGNATURE"

The client's signature verification failed.

Possible causes:

  • The client's private key does not match the authorized public key. Re-export and re-authorize.
  • The identity file is corrupted. Generate a new one with remi keygen --force on the client.

"Server fingerprint changed"

The client previously connected to this server and stored its fingerprint. The fingerprint no longer matches.

Possible causes:

  • The server regenerated its identity (e.g., ran remi keygen --force). This is expected.
  • A man-in-the-middle attack is changing the server's identity.

Solution: If you trust the server's new identity, clear the old fingerprint in the Remi web app under Settings > Known Hosts. Then reconnect; the new fingerprint will be stored.

"Server did not provide mutual authentication signature"

The server sent an auth result without signing the challenge.

Possible cause: Protocol mismatch. Ensure both server and client are running the same version of Remi.

Session Issues

"No active sessions found"

remi attach found no running sessions.

Solution: Check if the daemon is running:

remi ls

If nothing is listed, start a new session with remi my-project.

"Session has no Claude session ID"

remi --resume cannot resume because the session exited before Claude reported its session ID.

Solution: Start a new session instead:

remi my-project

Ambiguous Session ID

remi attach abc matches multiple sessions.

Solution: Provide a longer prefix:

remi attach abc12345

Hooks and auto-approve

Two Remi daemons in the same directory

Running remi --auto-approve (or plain remi) in two terminals open to the same project directory causes both daemons to stop processing hook events. Symptoms:

  • No GPU activity even when you expect auto-approve to run
  • Questions do not appear on your phone
  • ~/.remi/remi.log shows "Event bridge active" but nothing else

Cause: both daemons write their hook URL into the same .claude/settings.local.json. Each daemon sees the other as a sibling and refuses to lock onto a session to avoid cross-session hijacking. The check is cached — killing the extra daemon does not unblock the remaining one.

Workarounds:

  • Run only one Remi daemon per working directory.
  • If you need a second session in the same project, open the other terminal in a git worktree or a different path.
  • If you already hit the lockup, kill both daemons and restart a single one.

Tracked in issue #321.

Stale session after Claude restart

If Claude Code exits and restarts inside the same Remi-managed PTY, Remi detects the new session_id and re-locks. This is normal and you should see:

[Hooks] Claude restart detected (ended=false): <old-id> -> <new-id>

in ~/.remi/remi.log. If instead you see events being dropped as foreign ([Hooks] Dropped foreign ...), the classifier is seeing the new session as coming from a subagent rather than a restart. This can happen if Claude exits very quickly without emitting SessionEnd. Restart Remi to clear the stuck state.

"No GPU spike" with auto-approve enabled

Order of checks:

  1. Confirm the engine is reachable and the model is present: remi model status. If the engine has never started, the first evaluation triggers a fetch of both the helper and the default model, which can look like nothing is happening for a while on a slow connection.
  2. Confirm the model is actually resident: remi model ps. A cold load (after cache_idle/keep_alive unloads it) adds real latency to the next call.
  3. Confirm Remi captured the main session lock: grep for [Hooks] Transcript from PreToolUse: claude=... in ~/.remi/remi.log. No match → see "Two daemons" above.
  4. Confirm the permission request is from the main session and not a subagent: a subagent-tagged request is parked rather than evaluated at hook time, and is only evaluated if it actually renders on the PTY. See Auto-Approve guide: Subagent permissions.
  5. For deeper inspection, restart with REMI_HOOK_DEBUG=1 remi --auto-approve; every raw hook POST is written to ~/.remi/hook-diag.jsonl.

Phantom ❯ 1 typed into Claude Code chat

Fixed in Remi 0.5.1-dev.3. Earlier versions mis-routed subagent/team permission requests through auto-approve and injected "1" into the main PTY, which landed in your chat input prompt. If you see this on 0.5.1-dev.3 or later, please file an issue with the ~/.remi/remi.log excerpt and (if possible) a REMI_HOOK_DEBUG=1 capture.

Logs

Remi logs to ~/.remi/remi.log in wrapper mode (when you run remi or remi new directly) and ~/.remi/daemon.log in daemon mode (remi start, remi serve, remi --daemon, or the installed service); the hub and every session daemon it spawns share that one file. Check these files for detailed error information:

tail -f ~/.remi/remi.log        # wrapper mode
tail -f ~/.remi/daemon.log # daemon mode

If the log file does not exist or is empty, Remi may not have been able to create it. Verify that ~/.remi/ exists and is writable.

For hook event debugging, set REMI_HOOK_DEBUG=1 before starting Remi; every raw hook POST goes to ~/.remi/hook-diag.jsonl.