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

# Troubleshooting

> Fixes for the most common problems. Search for the exact error text you're seeing.

<Info>
  If your issue isn't listed here, open an issue at [github.com/yourhq/yourhq/issues](https://github.com/yourhq/yourhq/issues) with the exact error text, your host OS, and the output of `docker compose logs` for the failing service.
</Info>

***

## UI & access

<AccordionGroup>
  <Accordion title="UI keeps showing onboarding / 'no active workspace'">
    **What you see**

    You open `http://localhost:3000` and get sent back to onboarding even though you already connected Supabase.

    **Why it happens**

    The UI reads Supabase config from the workspace registry stored in the `ui-config` Docker volume. The registry is empty, unreadable, or was cleared when volumes were recreated.

    **Fix**

    Check the UI logs first:

    ```bash theme={null}
    cd ~/.yourhq
    docker compose logs ui
    ```

    Then either complete onboarding again (paste your Supabase URL and keys) or inspect the `ui-config` volume. If you intentionally reset volumes, this is expected. Supabase config is runtime-injected — rebuilding the UI image is not required.
  </Accordion>

  <Accordion title="Login fails silently or 'Invalid API key'">
    **What you see**

    You type your email/password, click Sign in — nothing happens, or you see `Invalid API key` / `Invalid login credentials`.

    **Why it happens**

    Either (a) the anon key in the UI doesn't match the Supabase project you're pointing at, or (b) you never created an auth user in Supabase. A fresh Supabase project has zero users.

    **Fix**

    1. In Supabase → **Project Settings → API**, confirm `Project URL` and `anon public` match what you entered in HQ Settings → Database.
    2. In Supabase → **Authentication → Users → Add user → Create new user**, create an email + password. Check **Auto Confirm User**.
    3. Log in with those credentials.
  </Accordion>

  <Accordion title="Onboarding wizard returns a 500">
    **What you see**

    You're going through the onboarding wizard and a step fails with a 500 error. `docker compose logs ui` shows `Origin mismatch` or `CSRF` error.

    **Why it happens**

    Next.js server actions enforce that the `Origin` header matches the host. When you access HQ through a proxy, Tailscale IP, or Codespaces forwarded URL, the origin doesn't match `localhost` and the action is rejected.

    **Fix**

    Set `ALLOWED_ORIGINS` in `~/.yourhq/.env` to the exact origin you're loading the UI from:

    ```bash theme={null}
    ALLOWED_ORIGINS=https://<codespace-name>-3000.app.github.dev,http://100.x.y.z:3000
    ```

    Then restart the UI:

    ```bash theme={null}
    docker compose up -d ui
    ```

    Codespaces: the installer sets this automatically if `CODESPACE_NAME` is in the environment. If you're using a VS Code tunnel, set it manually.
  </Accordion>

  <Accordion title="'Site can't be reached' from another device on the tailnet">
    **What you see**

    UI works at `http://localhost:3000` on the host but times out from your phone or another laptop at `http://100.x.y.z:3000`.

    **Why it happens**

    Local-only installs bind the UI to `127.0.0.1:3000`. Docker publishes the port on loopback only — the tailnet can't reach it.

    **Fix**

    Edit `~/.yourhq/.env`:

    ```
    UI_HOST_PORT=0.0.0.0:3000
    FILES_API_HOST_PORT=0.0.0.0:18790
    HOST_REACHABLE_URL=http://100.x.y.z    # your Tailscale IP
    NETWORKING_MODE=tailscale
    ```

    Recreate containers:

    ```bash theme={null}
    docker compose up -d --force-recreate
    ```

    See [Networking →](/self-host/networking)
  </Accordion>

  <Accordion title="'pull access denied' for ghcr.io/yourhq/* images">
    **What you see**

    ```
    Error response from daemon: pull access denied for ghcr.io/yourhq/yourhq-ui,
    repository does not exist or may require 'docker login'
    ```

    **Why it happens**

    During early access, the GHCR repo is private. Unauthenticated pulls are denied.

    **Fix**

    Create a GitHub PAT with `read:packages` scope, then log in:

    ```bash theme={null}
    echo "<your-PAT>" | docker login ghcr.io -u <your-github-username> --password-stdin
    docker compose pull
    docker compose up -d
    ```

    Alternatively, build locally (needs more RAM — see the t3.medium issue below):

    ```bash theme={null}
    docker compose build
    docker compose up -d
    ```
  </Accordion>
</AccordionGroup>

***

## Gateway & containers

<AccordionGroup>
  <Accordion title="Gateway container keeps restarting">
    **What you see**

    ```
    $ docker compose ps
    NAME               STATUS
    yourhq-gateway     Restarting (1) 8 seconds ago
    ```

    **Why it happens**

    The gateway entrypoint chains several steps: `openclaw onboard`, Xtigervnc, D-Bus, XFCE, websockify. Any step failing exits non-zero and Docker loops.

    **Fix**

    Tail the logs and find the last step that ran:

    ```bash theme={null}
    docker compose logs --tail=200 gateway
    ```

    Common culprits:

    * **`openclaw onboard` exits non-zero** — usually a bad `SUPABASE_SERVICE_ROLE_KEY` or Node version mismatch. Check: `docker compose exec gateway node --version` (must be v24.x). Re-confirm the service role key in Supabase → Settings → API.
    * **Xtigervnc won't start (stale lock files)** — clear the state volume: `docker compose down && docker volume rm yourhq-gateway-state && docker compose up -d gateway`.
    * **D-Bus socket never appeared** — force recreate: `docker compose up -d --force-recreate gateway`.
  </Accordion>

  <Accordion title="noVNC shows a black screen">
    **What you see**

    You open `http://<host>:6901/vnc.html`, click Connect — a black viewport with no cursor, no desktop.

    **Why it happens**

    Xtigervnc is up, but the XFCE session died. Almost always a D-Bus socket issue — XFCE won't start xfwm or xfce4-panel without a session bus.

    **Fix**

    Check the logs inside the gateway:

    ```bash theme={null}
    docker compose exec gateway tail -50 /home/openclaw/xfce.log
    docker compose exec gateway tail -20 /home/openclaw/dbus.log
    ```

    Force recreate usually fixes it:

    ```bash theme={null}
    docker compose up -d --force-recreate gateway
    ```

    If it still fails, clear the state volume (destroys agent workspace and OpenClaw auth — you'll need to re-OAuth):

    ```bash theme={null}
    docker compose down
    docker volume rm yourhq-gateway-state
    docker compose up -d
    ```
  </Accordion>

  <Accordion title="noVNC websockify.log shows 'Cannot assign requested address'">
    **What you see**

    `~/.vnc/websockify.log` ends with:

    ```
    [Errno 99] Cannot assign requested address
    ```

    **Why it happens**

    Websockify is trying to bind to a non-existent interface. Tailscale runs on the host, not inside the container — the gateway only knows `0.0.0.0` and `127.0.0.1`.

    **Fix**

    Ensure `.env` has:

    ```
    NOVNC_BIND=local
    ```

    `NOVNC_BIND=local` makes websockify bind to `0.0.0.0:6901` inside the container. Port 6901 is not mapped to the host — the UI proxies noVNC through its own `/api/novnc` route over Docker's internal network.

    Then: `docker compose up -d --force-recreate gateway`
  </Accordion>

  <Accordion title="Tailscale shows the gateway as dead or missing">
    **What you see**

    `tailscale status` doesn't show the gateway, or shows an old `yourhq-gateway` node as inactive.

    **Why it happens**

    Tailscale runs on the **host**, not inside the gateway container. Earlier versions ran it inside the container — those docs are outdated.

    **Fix**

    Check Tailscale on the host:

    ```bash theme={null}
    sudo tailscale status
    sudo tailscale ip -4
    ```

    If missing, re-run the host install:

    ```bash theme={null}
    curl -fsSL https://tailscale.com/install.sh | sh
    sudo tailscale up --authkey=tskey-auth-... --hostname="yourhq-$(hostname)"
    ```

    Update `.env` with `HOST_REACHABLE_URL=http://<new-ip>` and recreate: `docker compose up -d --force-recreate`.
  </Accordion>

  <Accordion title="Gateway logs show 'registering gateway ... failed'">
    **What you see**

    ```
    Registering gateway default in Supabase ...
      registration failed (Supabase unreachable or gateways table missing — will retry from daemon)
    ```

    **Why it happens**

    Either `SUPABASE_SERVICE_ROLE_KEY` is wrong, or the `gateways` table doesn't exist because migrations were never run.

    **Fix**

    1. Copy the service role key again from Supabase → Settings → API → `service_role` (not the anon key). Update it in HQ Settings → Database or in `.env`.
    2. Confirm migrations are complete: run every file in `db/migrations/` in order from Supabase SQL Editor.
    3. Restart: `docker compose restart gateway`.

    The log should change to `registered (reachable at http://...)`.
  </Accordion>
</AccordionGroup>

***

## Agents

<AccordionGroup>
  <Accordion title="Agent stuck in 'provisioning' for more than 2 minutes">
    **What you see**

    You create an agent in the UI. Status shows `provisioning` and never changes.

    **Why it happens**

    The provision command is leased by the `runner` container, which runs `add-agent.sh`. Something in that script failed — template branch missing, git repo corruption, or a Supabase write blocked by RLS.

    **Fix**

    Tail the runner:

    ```bash theme={null}
    docker compose logs -f runner
    ```

    Common causes:

    * **`fatal: A branch named 'template/cofounder' not found`** — `TEMPLATES_SOURCE` pointed at a repo missing that template. Clear the source (`TEMPLATES_SOURCE=` in `.env`) and restart the gateway so it uses bundled templates.
    * **`permission denied` writing to `/home/openclaw/...`** — volume owned by wrong UID. `docker compose down && docker volume rm yourhq-gateway-state && docker compose up -d`.
    * **HTTP 401/403 writing to Supabase** — service role key wrong. See gateway registration issue above.

    If the command is simply stuck with no activity, manually mark it failed to unblock the UI:

    ```sql theme={null}
    -- in Supabase SQL Editor
    update agent_commands set status='failed', error='manual cancel'
    where status='in_progress' and leased_at < now() - interval '5 minutes';
    ```
  </Accordion>

  <Accordion title="Agent never responds to messages">
    **What you see**

    You send a DM to your agent's Telegram/Discord bot. No reply.

    **Why it happens (Telegram / Discord)**

    99% of the time: you skipped the pairing step. OpenClaw's default policy is `pairing` — the bot won't engage until you pair your account to the agent.

    **Fix (Telegram / Discord)**

    1. Send any message to the bot. It should reply with a 6-digit pairing code.
    2. Open the UI → agent detail page → **Pairing Code** field → paste the code → submit.
    3. Send another message. The agent will respond.

    If the bot doesn't send a pairing code at all, it means the bot token is invalid or `add-agent.sh` never ran successfully — check runner logs: `docker compose logs runner | grep provision`.

    **Fix (Slack)**

    1. Verify the App-Level Token (`xapp-...`) has the `connections:write` scope.
    2. Verify the Bot Token (`xoxb-...`) has `chat:write`, `im:history`, `im:read`, `im:write`.
    3. Check runner logs: `docker compose logs runner | grep provision`.
    4. Check gateway logs: `docker compose logs gateway | grep slack`.
  </Accordion>

  <Accordion title="Agent responds but seems to have forgotten context">
    **What you see**

    You ask the agent something it should know from a previous conversation — it acts like it has no idea.

    **Why it happens**

    Agent memory lives in files on the git branch (e.g., `MEMORY.md`). The agent reads and updates these files during sessions. If the state volume was recreated, or the agent's branch was reset, memory is gone.

    **Fix**

    Check if the agent's branch exists:

    ```bash theme={null}
    docker compose exec gateway git --git-dir=/home/openclaw/.openclaw/agents/<slug>/.git log --oneline -5
    ```

    If the branch is missing or corrupt, the agent was re-provisioned from template — it starts fresh. You'll need to re-share context.

    To protect against this in the future: set `GIT_REMOTE_URL` in `.env` to sync agent branches to GitHub/Gitea. See [Operations →](/self-host/operations)
  </Accordion>

  <Accordion title="Agent is running but not doing background work">
    **What you see**

    Automation rules are set up, inbox items appear in Settings → System → Inbox, but the agent never processes them.

    **Why it happens**

    The dispatcher checks six conditions before waking an agent. Any one can block it:

    | Condition                | What to check                                                                             |
    | ------------------------ | ----------------------------------------------------------------------------------------- |
    | Agent paused             | Agent status in UI — must be `ready`                                                      |
    | Budget exceeded          | Agent budget section — hard cutoff may be blocking                                        |
    | Another instance running | Check for a stuck openclaw process: `docker compose exec gateway ps aux \| grep openclaw` |
    | Cooldown active          | Inbox items may be rate-limited per agent                                                 |
    | Active lease             | A command may be leased but stuck — check `agent_commands` table                          |

    **Fix**

    1. Check agent status: Agents → select agent → status must show `ready`, not `paused`.
    2. Check budget: scroll to Usage & Budget — if hard cutoff is hit, raise the limit or wait for next period.
    3. Check dispatcher logs: `docker compose logs -f dispatcher`
    4. If a command is stuck: mark it failed in Supabase SQL Editor (see provisioning fix above).

    See [Inbox dispatch reference →](/reference/inbox-dispatch)
  </Accordion>

  <Accordion title="Agent skills are not executing">
    **What you see**

    The agent responds to messages but doesn't use its skills — it describes what it would do rather than doing it, or says it can't find the skill.

    **Why it happens**

    Skills are shell scripts or markdown files on the agent's git branch under `skills/`. If the branch wasn't seeded correctly from the template, the skills directory may be empty or missing.

    **Fix**

    Inspect the agent's skills directory:

    ```bash theme={null}
    docker compose exec gateway ls /home/openclaw/.openclaw/agents/<slug>/skills/
    ```

    If empty: the agent was provisioned without template content. Re-provision by deleting and recreating the agent (the branch will be re-seeded from template on provision).

    If the directory exists but skills aren't running: check the agent's OpenClaw config (`openclaw.json`) on its branch — the `skills` path must point at the right directory.
  </Accordion>

  <Accordion title="openclaw models auth login hangs after OAuth">
    **What you see**

    You run:

    ```bash theme={null}
    docker compose exec gateway openclaw models auth login \
      --provider openai-codex --set-default
    ```

    It prints a URL, you complete OAuth in your browser — then the CLI just sits there indefinitely.

    **Why it happens**

    OpenClaw's OAuth flow tries a loopback HTTP callback on `localhost:1455` first, then falls back to paste. If you're completing OAuth on a different machine than the gateway (common with remote servers), the callback never fires — but the CLI waits for it forever.

    **Fix**

    Pre-occupy port 1455 to force the paste fallback:

    ```bash theme={null}
    # Terminal 1 — hold the port
    docker compose exec gateway python3 -m http.server 1455
    ```

    ```bash theme={null}
    # Terminal 2 — run the login (it will prompt for paste)
    docker compose exec gateway openclaw models auth login \
      --provider openai-codex --set-default
    ```

    Complete OAuth in your browser, copy the redirect URL (`http://localhost:1455/?code=...`), paste it into terminal 2. You should see `Auth profile saved`. Kill the server in terminal 1.
  </Accordion>
</AccordionGroup>

***

## Installer

<AccordionGroup>
  <Accordion title="'Docker is not installed' on Mac or Windows">
    **Why it happens**

    The auto-install path (`curl | sh get.docker.com`) is Linux-only. Docker on Mac/Windows is a GUI app and can't be installed from a script.

    **Fix**

    * **macOS** — download [Docker Desktop for Mac](https://docs.docker.com/desktop/install/mac-install/), drag to Applications, launch it, wait for the whale icon, re-run the installer.
    * **Windows** — install [WSL2](https://learn.microsoft.com/windows/wsl/install), then Docker Desktop, then launch it, and re-run the installer from a WSL shell.
  </Accordion>

  <Accordion title="curl | bash install doesn't show prompts">
    **Why it happens**

    Bash pipes can buffer stderr or swallow `/dev/tty` reads in some terminals.

    **Fix**

    Clone the repo and run the script directly:

    ```bash theme={null}
    git clone https://github.com/yourhq/yourhq.git
    cd yourhq
    ./installer/install.sh
    ```

    Same prompts, guaranteed interactive.
  </Accordion>

  <Accordion title="t3.medium becomes unreachable during 'docker compose build'">
    **Why it happens**

    Building all four images in parallel peaks well past 4 GB RAM. A t3.medium with no swap has no room — the OOM killer reaps sshd or dockerd.

    **Fix**

    Preferred: **pull prebuilt images instead of building**:

    ```bash theme={null}
    docker compose pull
    docker compose up -d
    ```

    If you must build, add swap first:

    ```bash theme={null}
    sudo fallocate -l 8G /swapfile && sudo chmod 600 /swapfile
    sudo mkswap /swapfile && sudo swapon /swapfile
    echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
    ```

    Then build one service at a time:

    ```bash theme={null}
    docker compose build ui
    docker compose build gateway
    docker compose build dispatcher
    docker compose build runner
    ```
  </Accordion>
</AccordionGroup>

***

## Database & data

<AccordionGroup>
  <Accordion title="Migration fails with 'relation already exists'">
    **What you see**

    SQL Editor stops with `ERROR: relation "contacts" already exists` or similar.

    **Why it happens**

    You ran a migration against a project where some tables already exist (from a previous partial run or an older schema version).

    **Fix**

    If this is a throwaway project where losing data is fine:

    ```sql theme={null}
    DROP SCHEMA public CASCADE;
    CREATE SCHEMA public;
    GRANT ALL ON SCHEMA public TO postgres, anon, authenticated, service_role;
    ```

    Then run every file in `db/migrations/` in filename order again.

    <Warning>
      This destroys all data in the `public` schema. Back up first if you have anything worth keeping.
    </Warning>

    If it's a live project, skip the failing statement and run the rest manually — but starting with a fresh Supabase project is usually faster.
  </Accordion>

  <Accordion title="UI loads but all tables appear empty">
    **What you see**

    You're logged in and the dashboard renders, but contacts/tasks/agents lists are empty even though rows exist in Supabase.

    **Why it happens**

    Row-level security is blocking reads. Either the `authenticated` role is missing `USAGE` on the schema, or table-level grants weren't applied.

    **Fix**

    In Supabase SQL Editor:

    ```sql theme={null}
    GRANT USAGE ON SCHEMA public TO authenticated;
    GRANT ALL ON ALL TABLES IN SCHEMA public TO authenticated;
    GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO authenticated;
    ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO authenticated;
    ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated;
    ```

    Refresh the UI. If data still doesn't appear, check the browser console — you may see JWT issues (anon key mismatch, expired session). Log out and back in.
  </Accordion>
</AccordionGroup>

***

## Performance

<AccordionGroup>
  <Accordion title="First run is very slow to boot">
    **Why it happens**

    Pulling the prebuilt images from GHCR the first time takes a while — the gateway image alone is \~1.5 GB (Xtigervnc, XFCE, Chrome, OpenClaw, Node 24). Docker caches them after the first pull.

    **Fix**

    Just wait. For progress visibility, pull explicitly before starting:

    ```bash theme={null}
    docker compose pull   # shows per-layer progress
    docker compose up -d
    ```
  </Accordion>

  <Accordion title="noVNC feels laggy">
    **Why it happens**

    The gateway runs Chrome + XFCE + OpenClaw simultaneously — \~1.5 GB RAM at idle. On a t3.small (2 GB) you're likely swapping. Websockify also streams uncompressed framebuffer diffs, which is bandwidth-intensive over public internet.

    **Fix**

    * Upgrade to t3.medium (4 GB RAM) or larger
    * Access noVNC via Tailscale (direct peer-to-peer, much better throughput than going via public internet)
    * In the noVNC UI (top-left gear icon): set quality to `6` and compression to `9` — cuts bandwidth \~3x
  </Accordion>
</AccordionGroup>

***

## Tired of debugging infrastructure?

If you'd rather focus on agents than Docker and networking, [HQ hosted](/hosted/getting-started) runs the same platform without any infrastructure to manage.

***

## Getting more help

If nothing above matches, open an issue at **[github.com/yourhq/yourhq/issues](https://github.com/yourhq/yourhq/issues)** with:

* The exact error text (copy/paste, not a screenshot)
* `docker compose logs` output for the failing service — last 200 lines
* Host info: `uname -a`, cloud provider + instance type, or "Mac/Linux local"
* Install method: `curl | bash`, direct clone, manual

### Diagnostic bundle

To gather everything at once:

```bash theme={null}
bash scripts/diagnostic-bundle.sh > diag.txt
```

This collects: `docker compose ps`, recent logs for each service, compose config with secrets redacted, `.env` keys (values redacted), `docker --version`, `tailscale status`, host OS info, and OpenClaw version. Attach `diag.txt` to your issue.

***

See also: [Networking](/self-host/networking) · [Configuration](/reference/configuration) · [Agents](/concepts/agents) · [Database schema](/reference/database-schema)
