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-projectorremi --daemon. - Wrong port. Check if you customized the port with
--portorREMI_PORT. - If you started with
--localor--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) oripconfig getifaddr en0(macOS). - In wrapper mode, the WebSocket server may have silently failed to start. Check
~/.remi/remi.logfor 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 --forceon 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.logshows "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:
- 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. - Confirm the model is actually resident:
remi model ps. A cold load (aftercache_idle/keep_aliveunloads it) adds real latency to the next call. - Confirm Remi captured the main session lock: grep for
[Hooks] Transcript from PreToolUse: claude=...in~/.remi/remi.log. No match → see "Two daemons" above. - 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.
- 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.