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

# Troubleshooting

> Reading the doctor report, and the common reasons a self-hosted deployment does not come up.

export const OssVersion = ({lang = "en"}) => <p className="text-sm text-gray-500 dark:text-gray-400">
    {lang === "zh" ? "对应 mirobody " : "Written for mirobody "}
    <a href="https://github.com/thetahealth/mirobody/tree/83362582a3f8add278456a81eefe2f87ba5898d2">
      <code>1.5.1</code>
    </a>
  </p>;

export const OssLink = ({path = "", children}) => {
  const base = "https://github.com/thetahealth/mirobody";
  const commit = "83362582a3f8add278456a81eefe2f87ba5898d2";
  const href = !path ? base + "/tree/" + commit : base + (path.endsWith("/") ? "/tree/" : "/blob/") + commit + "/" + path.replace(/\/$/, "");
  return <a href={href}>{children ?? <code>{path}</code>}</a>;
};

export const Fact = ({k, code = false, sep = ", "}) => {
  const facts = {
    "version": "1.5.1",
    "commit": "83362582a3f8add278456a81eefe2f87ba5898d2",
    "commitShort": "8336258",
    "repo": "https://github.com/thetahealth/mirobody",
    "python": "3.12",
    "port": 18060,
    "url": "http://localhost:18060",
    "pgPort": 18062,
    "redisPort": 18069,
    "account": "you@mirobody.ai",
    "accounts": ["you@mirobody.ai", "mom@mirobody.ai"],
    "code": "111111",
    "mcpUrlTtlDays": 30,
    "llmKeys": ["OPENROUTER_API_KEY", "DASHSCOPE_API_KEY", "GOOGLE_API_KEY", "OPENAI_API_KEY", "ANTHROPIC_API_KEY", "DEEPSEEK_API_KEY"],
    "cli": ["serve", "dev", "worker", "doctor", "parse", "import", "resolve", "mcp", "migrate-observations", "recode"],
    "tools": {
      "mcp": ["query_genetic_data", "query_health_indicators", "query_medications", "resolve_indicator", "convert_unit", "normalize_unit"],
      "gated": ["query_genetic_data", "query_health_indicators", "query_medications"]
    },
    "readme": {
      "en": {
        "tagline": "Self-hosted AI health data engine: every source, one standard, answers that cite their source.",
        "stages": [{
          "mark": "①",
          "name": "Collect",
          "what": "Lab reports, wearables, phone photos, genetic files, all pulled in. The source file is kept as it was, so every indicator points back to the page it was read from."
        }, {
          "mark": "②",
          "name": "Translate",
          "what": "One name to one code, one unit to UCUM, offline and deterministic. `A1c`, `HbA1c` and `Glycated Hemoglobin` become the same test here, and `头疼` and `headache` the same complaint (ICPC-3)."
        }, {
          "mark": "③",
          "name": "Agent",
          "what": "Ask over the coded record. Trend a value by minute, hour, day, week or month; get count, min, max, avg or change over any window in one call; compare across labs and devices, because they share one code. It charts the result in its reply, reads medications and genetic variants too, and names the file every number came from."
        }]
      },
      "zh": {
        "tagline": "自托管的 AI 原生健康数据引擎：任何来源，一套标准，每个答案都有出处。",
        "stages": [{
          "mark": "①",
          "name": "收集 Collect",
          "what": "化验单、穿戴设备、手机照片、基因文件，都收进来。源文件原样留下，每一项指标都能指回它被读出来的那一页。"
        }, {
          "mark": "②",
          "name": "转译 Translate",
          "what": "一个名字解析成一个码，一个单位统一到 UCUM，全程离线、结果确定。`A1c`、`HbA1c`、`糖化血红蛋白` 在这一层变成同一项检查，`头疼` 和 `headache` 也成了同一条主诉（ICPC-3）。"
        }, {
          "mark": "③",
          "name": "智能体 Agent",
          "what": "在编码后的记录上提问。按分钟、小时、天、周、月给出趋势，一次调用就能算出计数、最小值、最大值、均值和变化量；同一个码，跨化验所、跨设备直接比较。图表画在回复里，用药记录和基因型数据也读得了，每个数字都说明出自哪份文件。"
        }]
      }
    },
    "source": {
      "cli": "mirobody/cli.py",
      "tools": "mirobody/agent/tools"
    }
  };
  const value = k.split(".").reduce((o, p) => o == null ? undefined : o[p], facts);
  if (value === undefined) return <span>{"[unknown fact " + k + "]"}</span>;
  const items = Array.isArray(value) ? value : [value];
  return <>
      {items.map((item, i) => <span key={i}>
          {i > 0 ? sep : null}
          {code ? <code>{String(item)}</code> : String(item)}
        </span>)}
    </>;
};

<OssVersion lang="en" />

Start with the doctor report and the container log. Most failures name their own fix in one of the two.

```bash theme={null}
docker compose exec mirobody python -m mirobody doctor   # which model each surface selected
docker compose logs --tail 80 mirobody                  # the server's own log
```

## The doctor report

`mirobody doctor` prints one line for the keys it found, then one line per surface:

| Line                  | Meaning                                                                                                                                                  |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `keys present : none` | No model key is set. ① Collect and ② Translate still work; file extraction and the agent do not. Put one key in `.env` and run `docker compose restart`. |
| A surface marked `OK` | The entry and model that surface selected.                                                                                                               |
| A surface marked `--` | Nothing is available for that surface; the next line names the missing key or entry.                                                                     |
| `retired keys`        | A key from an earlier release that is no longer read. Move the setting to a `MODELS` entry or a `UTILS_*` route in `config.llm.yaml`.                    |
| `unread fields`       | A field in a `MODELS` entry that nothing reads, usually a misspelling.                                                                                   |

## Startup failures

| What you see                                                        | Cause and fix                                                                                                                                                                                                                    |
| ------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `deploy.sh` stops: a port is held by another container              | Another project publishes <Fact k="port" />, <Fact k="pgPort" /> or <Fact k="redisPort" />. `deploy.sh` does not stop containers it does not own: free the port, or change this project's ports.                                 |
| `deploy.sh` stops: a Docker network already uses the stack's subnet | `compose.yaml` pins one subnet, so only one checkout runs at a time. Remove the unused network the message names, or move this stack to a free subnet and point `PG_HOST` and `REDIS_HOST` at the new addresses in your overlay. |
| Compose rejects a named volume (`Host path binding is rejected`)    | Rootless or hardened Docker. Copy <OssLink path="compose.override.yaml.example" /> to `compose.override.yaml` and create the directories it lists.                                                                               |
| Image pulls fail, or the build cannot reach Docker Hub              | `deploy.sh` falls back to a registry mirror when Docker Hub does not answer. Behind a proxy, the Docker daemon itself needs the proxy setting, not only your shell.                                                              |
| The first start takes many minutes                                  | The first boot installs the Python dependencies into a volume before the server binds its port. Set `PIP_INDEX_URL` in `.env` to use a closer package index.                                                                     |
| The server refuses to start with `PRODUCTION: true`                 | Predefined sign-in codes or a `REPLACE_THIS_VALUE_IN_PRODUCTION` placeholder remain. The log names which; see [Deploy on a Server](/en/deployment/production#production-posture).                                                |
| `mirobody serve` finds no configuration                             | `config.yaml` is not part of the PyPI package. Run from a checkout, or use `mirobody dev`, which needs no configuration file.                                                                                                    |
| `mirobody dev` exits asking for a Postgres                          | Pass `--pg-url`, or set `PG_URL` or `DATABASE_URL`. The database needs the pgvector extension.                                                                                                                                   |

## Runtime problems

| What you see                                                  | Cause and fix                                                                                                                                                 |
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| A LOINC lookup raises on a fresh clone                        | The terminology bundle is stored with Git LFS and the clone holds a pointer file. Run `git lfs install && git lfs pull`.                                      |
| Device sync never runs, while the rest works                  | Redis is unreachable. Every other feature degrades cleanly; the vendor pull does not.                                                                         |
| Model calls fail with `Cannot connect to host` behind a proxy | A container does not inherit the shell's proxy. Set `HTTP_PROXY` and `HTTPS_PROXY` in `.env`; `compose.yaml` passes them to the server.                       |
| Uploads are stored but no readings appear                     | No vision or text model is selected (see the doctor report), or `ENABLE_INDICATOR_EXTRACTION` is `0`.                                                         |
| Sign-in with the demo account fails                           | `SEED_DEMO_DATA` was `false` at first start, or an overlay replaced `EMAIL_PREDEFINE_CODES`; overlay dictionaries replace, they do not merge.                 |
| A device provider does not appear                             | Its credentials are missing, so it skipped itself at startup; the boot log says which. See [Device Providers](/en/providers/using-providers#troubleshooting). |

Anything not covered here makes a useful issue on [GitHub](https://github.com/thetahealth/mirobody/issues): include the doctor report and the last lines of the container log, with personal data removed.
