> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ollim.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting

> Diagnose common issues with startup, sessions, scheduling, and Google OAuth.

When something goes wrong, start with the startup checks below, then look
through the categorized issues. Most problems trace back to missing
environment variables, stale PID files, or corrupt data files — all
recoverable.

<Tip>
  Before diving into manual troubleshooting, run `ollim-bot doctor` — it checks
  environment variables, data directory, timezone, routines, reminders, tool
  policy, state files, and Claude authentication in one pass. See the
  [`doctor` CLI reference](/development/cli-reference#doctor) for details.
</Tip>

## Startup failures

These are the most common blockers when launching `ollim-bot`.

### Missing environment variables

`main()` validates all three required variables on startup. If any are missing,
the bot shows all missing vars at once with hints and exits:

```text theme={null}
Missing required env vars in .env:
  DISCORD_TOKEN    (bot token from Discord Developer Portal)
  OLLIM_USER_NAME  (your first name — the bot will call you this)
  OLLIM_BOT_NAME   (your bot's name, e.g. Ollim)
```

Set the missing variables in your `.env` file (at the project root) and restart.

### Invalid Discord token

When `bot.start()` receives a `LoginFailure` exception from discord.py, the
bot prints an actionable error and exits with code 1:

```text theme={null}
Invalid Discord token. Check DISCORD_TOKEN in .env
Get a new token: Discord Developer Portal > Bot > Reset Token
```

Regenerate your token in the Discord Developer Portal and update `DISCORD_TOKEN`
in `.env`.

### Message Content Intent not enabled

When `bot.start()` raises `PrivilegedIntentsRequired`, the bot exits with
code 1:

```text theme={null}
Message Content Intent is not enabled.
Enable it: Discord Developer Portal > Bot > Privileged Gateway Intents
```

The bot requires the **Message Content Intent** to read message text. The
[quickstart's Discord bot setup](/getting-started/quickstart#create-a-discord-bot)
shows where to find this toggle.

### Discord API 401 during authentication

This is caught before `bot.start()` — during the Claude auth DM flow, when
the bot uses the Discord REST API directly. If the API returns a 401:

```text theme={null}
Discord API returned 401 — DISCORD_TOKEN appears invalid.
Check that DISCORD_TOKEN in .env matches the token from
Discord Developer Portal > Bot > Reset Token.
```

Exits with code 1. This catches the same underlying issue as
[Invalid Discord token](#invalid-discord-token) (a bad token) but earlier in
the startup sequence, before the bot fully connects.

### Bot already running

The bot writes its PID to `~/.ollim-bot/state/bot.pid` on startup and checks
whether that process is still alive:

* **Primary check**: `os.kill(pid, 0)` — works on all platforms
* **Linux enhancement**: additionally reads `/proc/<pid>/cmdline` to verify
  the process is actually `ollim-bot`, preventing false positives from recycled
  PIDs

If a running instance is detected:

```text theme={null}
ollim-bot is already running (pid 12345)
```

Corrupted PID files — non-numeric content or the file disappearing mid-read —
are handled gracefully and overwritten on the next startup.

If the previous process crashed without cleaning up the PID file, delete it
manually:

```bash theme={null}
rm ~/.ollim-bot/state/bot.pid
```

The file is normally deleted on exit via `atexit`.

### No owner found

If `bot.application_info()` returns no owner, the bot prints:

```text theme={null}
warning: no owner found; scheduler and DM disabled
```

The bot stays online but cannot send DMs, run scheduled routines, or start
the webhook server. The owner is automatically the Discord account that
created the application — this error usually means the application was
created by a team with no members.

### Discord API outage (503)

Transient Discord API outages return a `DiscordServerError` (HTTP 503).
The bot retries automatically up to 5 times with exponential backoff —
5s, 10s, 20s, 40s, 80s between attempts. During retries, the console
shows:

```text theme={null}
Discord API error (503 Service Unavailable) — retrying in 10s (attempt 2/5)
```

If all 5 retries fail, the bot gives up and exits with code 1:

```text theme={null}
Discord API error (503 Service Unavailable) — giving up after 5 retries.
Check https://discordstatus.com for outages.
```

If you see persistent 503 errors, check
[discordstatus.com](https://discordstatus.com) for ongoing incidents.
With `Restart=on-failure` in a systemd service, the bot restarts and
tries again automatically.

### Unexpected shutdown

The bot sends a DM before exiting on crash, SIGINT, or SIGTERM:

```text theme={null}
shutting down: received SIGTERM
```

Or for crashes:

```text theme={null}
shutting down: ConnectionError: gateway disconnected
```

The notification is best-effort — if the Discord connection is already down,
the DM is silently skipped. If you're running as a systemd service with
`Restart=on-failure`, the bot comes back automatically after unexpected exits.

### Claude auth not completing

On startup, the bot checks Claude authentication via the bundled CLI. If not
logged in, it DMs you an OAuth link and waits for you to complete sign-in.

If you don't receive the DM, verify your `DISCORD_TOKEN` is correct — the
bot uses the Discord REST API directly (not discord.py) to send the auth DM
before fully connecting. If the DM arrives but login fails after clicking the
link, run `ollim-bot auth login` manually to see the CLI output.

```bash theme={null}
# Check current auth status
ollim-bot auth status

# Manually trigger the login flow
ollim-bot auth login
```

If authentication fails repeatedly, verify your Claude subscription is active
and that the bundled CLI at `claude_agent_sdk/_bundled/` is intact — reinstalling
with `uv tool install --editable .` rebuilds it.

## Session issues

<AccordionGroup>
  <Accordion title="Session not resuming after restart">
    The bot reads `~/.ollim-bot/state/sessions.json` on startup. If the file is
    missing or empty, it starts a fresh session. Check that the file exists
    and contains a session ID string:

    ```bash theme={null}
    cat ~/.ollim-bot/state/sessions.json
    ```

    If the file contains a JSON object (starts with `{`), `load_session_id()`
    returns `None` and the bot starts fresh. This can happen if another tool
    writes JSON to the file. Replace it with just the session ID string.
  </Accordion>

  <Accordion title="Frequent compaction events">
    The Agent SDK auto-compacts conversations when they grow too long. Each
    compaction produces a new session ID and a `compacted` event in
    `session_history.jsonl`. This is normal behavior — the bot detects the
    ID change in `save_session_id()` and logs it automatically.

    If compaction happens too frequently, the conversation is growing fast.
    Use `/clear` to start fresh, or use `/compact` to trigger a manual
    compaction at a natural breakpoint.
  </Accordion>

  <Accordion title="Recovering session history">
    The append-only log at `~/.ollim-bot/state/session_history.jsonl` records every
    lifecycle event. To inspect it:

    ```bash theme={null}
    cat ~/.ollim-bot/state/session_history.jsonl
    ```

    Each line is a JSON object with `session_id`, `event`, `timestamp`, and
    `parent_session_id`. Use this to trace session transitions, find the last
    known good session ID, or understand what happened before a crash.

    To manually resume a specific session, write its ID to `sessions.json`:

    ```bash theme={null}
    echo -n "sess_abc123" > ~/.ollim-bot/state/sessions.json
    ```
  </Accordion>
</AccordionGroup>

## Data directory issues

All persistent state lives in `~/.ollim-bot/`. See the
[data directory reference](/configuration/data-directory) for the full layout.

<AccordionGroup>
  <Accordion title="Corrupt markdown files (routines, reminders, webhooks)">
    `read_md_dir()` catches `ValueError`, `yaml.YAMLError`, `TypeError`, and
    `KeyError` when parsing `.md` files. Corrupt files are logged as warnings
    and skipped — they do not crash the bot.

    To find corrupt files, check the bot's log output for warnings, then
    inspect or delete the offending file from `~/.ollim-bot/routines/`,
    `reminders/`, or `webhooks/`.
  </Accordion>

  <Accordion title="Corrupt JSONL files">
    `read_jsonl()` skips blank lines and lines that do not start with `{`.
    Lines that start with `{` but contain invalid JSON are logged as warnings
    and skipped — they do not crash the read. It also filters fields
    to only those known to the target dataclass, providing forward compatibility.

    If a JSONL file is entirely corrupted, delete it. The bot recreates these
    files on the next write:

    ```bash theme={null}
    rm ~/.ollim-bot/state/session_history.jsonl
    ```
  </Accordion>

  <Accordion title="Do not edit files while the bot is running">
    All writes use atomic temp-file-then-rename (`tempfile.mkstemp` +
    `os.replace`). Manual edits to files in `~/.ollim-bot/` while the bot is
    running risk being overwritten or causing inconsistent state. Stop the bot
    first, make edits, then restart.
  </Accordion>
</AccordionGroup>

<Warning>
  The `~/.ollim-bot/` directory is a git repository. If you manually edit
  files, the bot's auto-commit on next write will include your changes in
  its commit. Use `git log` inside the directory to review the change history.
</Warning>

## Google OAuth issues

<AccordionGroup>
  <Accordion title="Missing credentials.json">
    The Google integration requires `~/.ollim-bot/state/credentials.json` from the
    Google Cloud Console. Without it, all Google-related commands (`tasks`,
    `cal`, `gmail`) and agent tools fail. Follow the
    [Google integration setup guide](/getting-started/google-integration) to create
    and place this file.
  </Accordion>

  <Accordion title="Expired or invalid token">
    `~/.ollim-bot/state/token.json` is auto-generated after `/google-auth` and
    refreshed automatically. If the token is revoked (password change, manual
    revocation), the bot
    detects it automatically and sends you a message to reconnect. Run
    `/google-auth` to re-authenticate.

    If the automatic detection does not trigger (e.g., the bot was offline when
    the revocation happened), you can delete the token manually and reconnect:

    ```bash theme={null}
    rm ~/.ollim-bot/state/token.json
    ```

    Then run `/google-auth` in Discord.
  </Accordion>
</AccordionGroup>

## Scheduling issues

<AccordionGroup>
  <Accordion title="Routines or reminders not firing">
    The scheduler polls the `routines/` and `reminders/` directories every
    10 seconds and registers APScheduler jobs. Check:

    1. The bot printed `scheduler started: N jobs` on startup (visible in
       the console).
    2. The `.md` file has valid YAML frontmatter with a `cron` (routines) or
       `run-at` (reminders) field.
    3. The `id` field in the YAML is unique — duplicate IDs cause one to
       overwrite the other.
    4. The owner was found on startup (no `"warning: no owner found"` message).
       The scheduler does not start without an owner.
  </Accordion>

  <Accordion title="Ping budget exhausted">
    Background forks that exceed the ping budget get tool errors from
    `ping_user` and `discord_embed`. The user is not notified — the tool
    returns an error to the agent, which decides how to proceed.

    Check the budget state:

    ```bash theme={null}
    cat ~/.ollim-bot/state/ping_budget.json
    ```

    The `available` field shows remaining pings. The bucket refills 1 ping
    per 90 minutes, capped at a capacity of 5. Use `/ping-budget` in Discord
    to view a formatted status. See
    [ping budget](/scheduling/ping-budget) for details.
  </Accordion>
</AccordionGroup>

## Background fork issues

<AccordionGroup>
  <Accordion title="Background fork fails to start (SDK timeout)">
    Background fork client initialization can fail with a "Control request
    timeout" error from the Claude Agent SDK. The bot automatically retries
    up to 3 times with 5s and 15s backoff delays.

    If all 3 attempts fail, the error is logged and the bot sends you a DM
    that the background task failed. This is typically a transient issue —
    the next scheduled fire usually succeeds. If it persists, check your
    network connection and the Claude API status.
  </Accordion>

  <Accordion title="Background fork failure or timeout notification">
    When a background fork crashes or exceeds its timeout (`bg_fork_timeout`,
    default 30 minutes), the bot sends a best-effort DM notification:

    ```text theme={null}
    Background task timed out after 30 minutes: `[routine:daily-email-check]`
    ```

    Or for crashes:

    ```text theme={null}
    Background task failed: `[reminder:workout-nudge]` -- check logs for details.
    ```

    These messages are informational — the fork has already been cleaned up.
    If the task was a routine, the next scheduled fire will try again
    automatically. If it was a one-shot reminder, you may need to reschedule it.
  </Accordion>
</AccordionGroup>

## Fork issues

<AccordionGroup>
  <Accordion title="Reply-to-fork not working">
    Replying to a background fork message starts an interactive fork that
    resumes from that fork's session. This relies on
    `~/.ollim-bot/state/fork_messages.json`, which maps Discord message IDs to
    fork session IDs.

    Records older than 7 days are pruned on every read. If the background
    fork message is older than 7 days, the mapping no longer exists and
    the reply is treated as a normal message.
  </Accordion>

  <Accordion title="Fork appears stuck">
    Interactive forks have an idle timeout. The scheduler checks every 60
    seconds — after `idle_timeout` minutes of inactivity, it prompts the
    agent to exit. After another timeout period, it escalates with a
    stronger prompt. The agent always decides the exit strategy
    (`report_updates`, `exit_fork`, or `save_context`).

    If the fork is truly stuck, use the exit buttons on the fork embed, or
    run `/clear` to reset the entire session.
  </Accordion>
</AccordionGroup>

## Permission issues

<AccordionGroup>
  <Accordion title="Tools being silently denied">
    The default permission mode is `dontAsk`. In this mode, non-whitelisted
    tools are silently denied without prompting the user in Discord.

    Switch to a more permissive mode with the `/permissions` command:

    | Mode                | Behavior                                              |
    | ------------------- | ----------------------------------------------------- |
    | `dontAsk`           | Non-whitelisted tools silently denied (default)       |
    | `default`           | Non-whitelisted tools trigger Discord approval prompt |
    | `acceptEdits`       | File edits auto-approved, others prompt               |
    | `bypassPermissions` | All tools approved                                    |

    The `_session_allowed` set persists across interactive forks but resets
    on `/clear`.
  </Accordion>

  <Accordion title="Approval prompt not appearing">
    In `default` or `acceptEdits` mode, the bot sends a Discord message with
    reaction-based approval. The prompt has a 60-second timeout — if you
    miss it, the tool is auto-denied. Check that you are in a mode that
    sends prompts (`default` or `acceptEdits`, not `dontAsk`).
  </Accordion>
</AccordionGroup>

## Windows platform issues

<AccordionGroup>
  <Accordion title="Garbled Unicode output in CLI commands">
    Windows defaults to the system codepage (e.g., cp1252) which can
    corrupt Unicode characters in CLI output. The bot forces UTF-8
    encoding on `stdout` and `stderr` before running any subcommand, so
    all CLI paths (`ollim-bot`, `ollim-bot routine`, `ollim-bot reminder`,
    etc.) produce correct output.

    If you still see garbled text, verify your terminal supports UTF-8.
    In PowerShell, run `chcp 65001` to switch to UTF-8 manually.
  </Accordion>

  <Accordion title="Auto-updater fails to restart on Windows">
    When installed via `uv tool install`, the entry point on Windows is an
    `.exe` file — not a Python script. The auto-updater uses `sys.argv`
    directly to restart, which handles both `.exe` entry points and Python
    script invocations correctly. If the bot fails to restart after an
    update, verify that `ollim-bot` is on your `PATH` and was installed
    with `uv tool install --editable .`.
  </Accordion>
</AccordionGroup>

## Diagnostic files

Quick reference for where to look when debugging. Run
[`ollim-bot doctor`](/development/cli-reference#doctor) first — it validates
most of these files automatically and reports **PASS**, **WARN**, or **FAIL**
for each.

| File                                       | What it tells you                                   |
| ------------------------------------------ | --------------------------------------------------- |
| `~/.ollim-bot/state/sessions.json`         | Current session ID (or missing = no active session) |
| `~/.ollim-bot/state/session_history.jsonl` | Timeline of session lifecycle events                |
| `~/.ollim-bot/state/bot.pid`               | PID of running bot instance                         |
| `~/.ollim-bot/state/ping_budget.json`      | Current ping budget state and counters              |
| `~/.ollim-bot/state/pending_updates.json`  | Queued background fork summaries                    |
| `~/.ollim-bot/state/fork_messages.json`    | Discord message to fork session mappings            |
| `~/.ollim-bot/state/inquiries.json`        | Active button inquiry prompts                       |

<Tip>
  The `~/.ollim-bot/` directory is git-tracked. Run `git log --oneline`
  inside it to see a chronological record of all data changes.
</Tip>

## Next steps

<Columns cols={2}>
  <Card title="Data directory" icon="folder-open" href="/configuration/data-directory">
    Full layout of \~/.ollim-bot/ and file format details.
  </Card>

  <Card title="Session management" icon="rotate" href="/architecture/session-management">
    How sessions persist, compact, and recover across restarts.
  </Card>

  <Card title="Development guide" icon="code" href="/development/guide">
    Dev setup, running locally, and code conventions.
  </Card>

  <Card title="Configuration reference" icon="gear" href="/configuration/reference">
    All environment variables and their defaults.
  </Card>
</Columns>
