Skip to content

Troubleshooting

Daniel Ellison edited this page Mar 26, 2026 · 7 revisions

Troubleshooting

Common issues and how to fix them, organized by when they occur.

Startup failures

These errors cause Kai to exit immediately on launch.

"TELEGRAM_BOT_TOKEN is required in .env" Your .env file is missing or doesn't contain the bot token. Copy .env.example to .env and fill in your token from @BotFather.

"ALLOWED_USER_IDS is required in .env" Add your Telegram user ID to .env. Get it by messaging @userinfobot on Telegram. Multiple IDs can be comma-separated.

"ALLOWED_USER_IDS must be numeric Telegram user IDs (not usernames)" You put a username like @myname instead of a numeric ID. Telegram user IDs are numbers like 2114582497.

"WORKSPACE_BASE is not an existing directory" The path in WORKSPACE_BASE doesn't exist. Create it first (mkdir -p /path/to/projects) or remove the variable from .env if you don't need workspace switching.

Bot doesn't respond

Bot shows online but ignores messages Your Telegram user ID isn't in ALLOWED_USER_IDS. Unauthorized messages are silently dropped. Double-check your ID with @userinfobot.

Bot shows offline in Telegram Kai isn't running or can't reach Telegram's API. Check:

  • Is the process alive? (launchctl list | grep kai on macOS, systemctl status kai on Linux)
  • Check the log file for errors (kai.log in the project directory)
  • Can your machine reach the internet?
  • If using webhook mode, is your tunnel running? Try switching to polling mode temporarily (comment out TELEGRAM_WEBHOOK_URL) to isolate the issue

Claude errors

"Error: claude CLI not found" Claude Code isn't installed or isn't on the PATH. Install it from docs.anthropic.com and make sure the claude binary is accessible. If running as a service, check that your launchd/systemd PATH includes the directory where claude is installed.

"Error: Claude timed out" Claude took too long to respond. This can happen with complex tool-use chains, especially on Opus. The timeout is CLAUDE_TIMEOUT_SECONDS * 3 (default: 360 seconds). You can increase CLAUDE_TIMEOUT_SECONDS in .env if this happens frequently.

"Error: Claude process died, restarting on next message" The Claude subprocess crashed unexpectedly. This is usually transient — send your message again and Kai will start a fresh process. If it keeps happening, check kai.log for details.

"Error: No response from Claude" Claude returned nothing. This can happen if the process was interrupted (e.g., by /stop) at the wrong moment. Send your message again.

Workspace issues

"WORKSPACE_BASE is not set. Add it to .env and restart." You tried /workspace <name> but haven't configured WORKSPACE_BASE in .env. Add it and restart Kai. /workspace home always works regardless.

"Absolute paths are not allowed. Use a workspace name." Workspace names are resolved relative to WORKSPACE_BASE. Use just the directory name (e.g., /workspace kai), not a full path.

"Invalid workspace name." The name resolved to a path outside WORKSPACE_BASE (likely contains ../). Use a simple directory name.

"Path does not exist" The directory doesn't exist under WORKSPACE_BASE. Check spelling, or create it with /workspace new <name>.

Voice issues

"Voice messages are not enabled." Set VOICE_ENABLED=true in .env and restart Kai.

"Voice is enabled but dependencies are missing: ffmpeg" Install ffmpeg: brew install ffmpeg (macOS) or sudo apt install ffmpeg (Linux).

"Voice is enabled but dependencies are missing: whisper-cpp" Install whisper-cpp: brew install whisper-cpp (macOS) or build from source on Linux. The binary must be available as whisper-cli on your PATH. See Voice Setup for details.

"Voice is enabled but dependencies are missing: whisper model" Download the model: make models/ggml-base.en.bin from the project root.

"Couldn't make out any speech in that voice message." The audio was too quiet, too short, or mostly silence. Speak clearly and close to the microphone.

"TTS is not enabled." Set TTS_ENABLED=true in .env, install TTS dependencies with pip install -e '.[tts]', download voice models with make tts-model, and restart Kai.

TOTP issues

Bot doesn't prompt for a code even though TOTP is set up The sudoers rules may be missing or incorrect. Without them, the bot can't read the secret file via sudo and falls back to "not configured." Verify with python -m kai totp status - if it says "not configured" but you ran setup, check /etc/sudoers.d/kai. Also confirm the totp extra is installed (pip install -e '.[totp]').

"Session expired. Enter code from authenticator." but the code is rejected Make sure your authenticator app's clock is synced. TOTP codes are time-based - even 30 seconds of clock drift can cause failures. On most phones this syncs automatically, but check if you've manually set the time.

Locked out after too many failed attempts Wait for the lockout to expire (default 15 minutes), or reset TOTP entirely: sudo python -m kai totp reset. This removes the secret and attempts files. Re-run sudo python -m kai totp setup to reconfigure.

Can't run sudo python -m kai totp setup as the service account If the bot runs as a dedicated user (e.g., kai) without sudo access, log in as a user with sudo, cd to the project directory, activate the virtualenv, and run setup from there. The service account only needs the targeted sudoers rules for runtime - it doesn't need general sudo access.

"TOTP challenge expired" message The challenge window is 2 minutes by default (TOTP_CHALLENGE_SECONDS=120). If you don't enter the code in time, send any message to trigger a new challenge.

Protected installation issues

For full details on the protected installation workflow, see Protected Installation.

"Permission denied" when reading /etc/kai/env The sudoers rules may be missing or incorrect. Verify with sudo visudo -cf /etc/sudoers.d/kai. Re-run sudo python -m kai install apply to regenerate them.

Service starts but Claude can't find the claude binary The service's PATH must include ~/.local/bin/ for the service user (where the Claude Code native installer puts the binary). The generated plist/unit includes this, but if you manually edited the service definition, check the PATH.

"Python >= 3.13 required" during install apply The installer requires Python 3.13+. Install it and ensure it's the default python3 on your PATH, or install as python3.13 (the installer checks both).

Database not found after migration The installer migrates kai.db from the project root to /var/lib/kai/ on first apply. If you see database errors, check that KAI_DATA_DIR is set correctly in the service environment (the generated plist/unit handles this).

Always dry-run first Use sudo python -m kai install apply --dry-run to preview all changes before applying them.

Telegram transport issues

Bot doesn't respond in webhook mode If you set TELEGRAM_WEBHOOK_URL but the bot isn't responding:

  1. Check that your tunnel is running (curl https://yourdomain.com/health should return {"status": "ok"})
  2. Verify the URL in .env matches your tunnel's hostname and ends with /webhook/telegram
  3. Check kai.log for Telegram transport: webhook at startup - if you see polling instead, the URL isn't being read
  4. Try commenting out TELEGRAM_WEBHOOK_URL and restarting - if polling works, the issue is with the tunnel or webhook registration

Switching from webhook to polling Comment out or remove TELEGRAM_WEBHOOK_URL from .env and restart Kai. It falls back to polling automatically.

Health monitor

"Webhook health check has failed N consecutive times" The webhook health monitor runs every 5 minutes and checks the Telegram webhook status. After 3 consecutive failures (15 minutes), it sends a one-time admin notification. The counter resets on the next successful check. If you see this, check your tunnel status and Telegram API connectivity. The health monitor will automatically re-register the webhook when it detects issues.

Webhook issues

GitHub webhooks not arriving

  1. Check that your tunnel is running (curl https://yourdomain.com/health should return {"status": "ok"})
  2. Verify the webhook secret in GitHub matches WEBHOOK_SECRET in .env
  3. Check GitHub's webhook delivery log (Settings > Webhooks > Recent Deliveries) for error codes
  4. Make sure your tunnel config routes /webhook/* to localhost:8080

"GitHub webhook: invalid signature" in logs The WEBHOOK_SECRET in .env doesn't match the secret configured in GitHub. They must be identical.

Scheduling API returns 401 The X-Webhook-Secret header doesn't match WEBHOOK_SECRET. This header is required for all /api/* endpoints.

Webhooks and scheduling not working at all If WEBHOOK_SECRET is not set in .env, webhook and scheduling endpoints are disabled entirely (only /health is active). This is intentional — these endpoints require a secret for authentication. Set WEBHOOK_SECRET in .env and restart Kai. The /webhooks command will confirm which endpoints are active.

Service issues

Kai keeps restarting (macOS launchd) Check kai.log for the crash reason. Common causes:

  • Missing .env file (Kai exits immediately on missing required config)
  • claude not on the service's PATH (crashes on first message)
  • Python not found (wrong path in the plist ProgramArguments)

With KeepAlive set to true, launchd will keep restarting Kai after every crash.

Kai keeps restarting (Linux systemd) Same as above. Check logs with journalctl -u kai -f. Common causes are the same — missing config, claude not on PATH, or wrong Python path in the unit file.

"Sorry, my previous response was interrupted" This is normal after a crash or restart while Kai was mid-response. It means crash recovery is working. Resend your last message.

Logs

Kai logs to kai.log in the project directory (when running as a service) or to stdout (when running manually with make run). Key things to look for:

  • Kai starting — successful startup with model and user IDs
  • Restored workspace — workspace restored from previous session
  • Starting persistent Claude process — Claude subprocess launching
  • Claude stderr — debug output from Claude Code (at DEBUG level)
  • Any ERROR or WARNING lines — something went wrong

Clone this wiki locally