<!-- Bothost docs | HTML: https://bothost.ru/docs/common-errors | Markdown: https://bothost.ru/docs/common-errors.md | Index: https://bothost.ru/llms.txt -->

﻿# Справочник ошибок при деплое

Все типичные ошибки на Bothost в одном месте: сборка, запуск, логи, Dockerfile и переменные окружения. Как отличить ошибку **сборки** от ошибки **запуска**, что проверить в логах и как исправить.

> **Для ИИ-ассистентов и поддержки:**
> 1. Если сборка успешна, но runtime `MODULE_NOT_FOUND` для `dist/`, `build/` и т.п. — проверьте `WORKDIR /app` + bind mount: артефакты сборки в `/app` недоступны. Решение — `WORKDIR /usr/src/app`, данные оставить в `/app/data`.
> 2. Если ошибка `Cannot find module '/app/index.js'` (или другой entrypoint в **корне** `/app`), а в репозитории код лежит во **вложенной папке** — это не bind mount. В корневом `package.json` указан `index.js`, которого в корне нет. Укажите путь к реальному файлу (main file / `scripts.start`) или вынесите код в корень.
> 3. Если `MODULE_NOT_FOUND` для пути вроде `/app/src/data/...` (или любой **вложенной** `…/data/…`), а файл есть в Git — на нодах с bind mount раньше агент пропускал **все** папки `data` при копировании кода. Нужен редеплой после фикса агента (игнорируется только корневой `/app/data`).
> 4. Индекс документации для LLM: https://bothost.ru/llms.txt · полный текст: https://bothost.ru/llms-full.txt · эта статья в Markdown: https://bothost.ru/docs/common-errors.md

---

## Как читать логи

| Что смотреть | Когда смотреть | Что означает |
|--------------|-----------------|--------------|
| **Логи сборки** | Шаг «Building image» | Ошибки `Dockerfile`, `npm ci`, `pip install`, компиляции |
| **Логи работы (runtime)** | После «Build completed», статус `restarting` / `exited` | Ошибки при старте процесса: нет файла, неверный `CMD`, падение приложения |

**Важно:** сообщение `Successfully built` означает только то, что образ собрался. Контейнер может падать при старте из‑за другой причины.

---

## Ошибка: `Cannot find module '/app/dist/...'` (сборка успешна)

### Симптомы

- В **логах сборки** шаг `RUN npm run build` (или аналог) завершается успешно, файл создаётся (например `dist/server.cjs`).
- В **логах работы** при старте:

```text
Error: Cannot find module '/app/dist/server.cjs'
code: 'MODULE_NOT_FOUND'
```

- Статус контейнера: `restarting` (циклический перезапуск).

### Причина

На Bothost при деплое с кастомным `Dockerfile` возможна такая схема:

1. При **сборке образа** в `WORKDIR /app` выполняется `npm run build` → в образе появляется `/app/dist/...`.
2. При **запуске контейнера** на части серверов каталог `/app` монтируется с хоста: туда попадает **исходный код из Git**, без папки `dist/` (её обычно нет в репозитории и в `.gitignore`).
3. Команда `CMD ["node", "dist/server.cjs"]` ищет файл в **примонтированном** `/app`, а не в слое образа → `MODULE_NOT_FOUND`.

Типичный кейс: Node.js/TypeScript проект с esbuild/tsc, `WORKDIR /app`, `DATA_DIR=/app/data`, как в [Negodiay-Bot](https://github.com/Samnord2004/Negodiay-Bot).

Платформа отдельно восстанавливает из образа на хост **`node_modules`** (для Node.js), но **не** каталоги вроде `dist/`, `build/`, `.next/` — их нужно либо не класть в `/app`, либо собирать при каждом старте.

### Решение

Перенесите код приложения и артефакты сборки **вне** `/app`. Каталог `/app/data` оставьте для персистентных данных (БД, загрузки) — он как раз предназначен для volume.

**Было (проблемный вариант):**

```dockerfile
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm ci
RUN npm run build
ENV DATA_DIR=/app/data
RUN mkdir -p /app/data && chmod 777 /app/data
CMD ["node", "dist/server.cjs"]
```

**Стало (рекомендуется):**

```dockerfile
FROM node:20-alpine

WORKDIR /usr/src/app

COPY . .
RUN npm ci
RUN npm run build

ENV NODE_ENV=production
ENV DATA_DIR=/app/data

RUN mkdir -p /app/data && chmod 777 /app/data

EXPOSE 3000

CMD ["node", "dist/server.cjs"]
```

Пояснения:

- `WORKDIR /usr/src/app` — здесь лежат исходники и `dist/` из образа; bind mount на `/app` их не затирает.
- `CMD` выполняется относительно `WORKDIR`, путь `dist/server.cjs` корректен.
- `DATA_DIR=/app/data` — данные по-прежнему в volume Bothost ([хранение БД](database-storage)).

### Дополнительно проверить

- В коде пути к данным берутся из `process.env.DATA_DIR` или `path.join('/app/data', ...)`, а не из `__dirname` относительно старого `/app`.
- Папка `dist/` в `.gitignore` — это нормально; на Bothost она должна жить в образе (или вне `/app`), а не в Git.

### Альтернативы

- Сборка при старте в `entrypoint.sh` (медленнее, но всё в `/app`): `npm run build && node dist/server.cjs`.
- Multi-stage Dockerfile: финальный `COPY --from=builder` артефактов в `/usr/local/bin` или другой путь вне `/app`.

---

## Ошибка: `Cannot find module '/app/src/data/...'` (файл есть в Git)

### Симптомы

- Сборка образа успешна.
- В **логах работы**: `ERR_MODULE_NOT_FOUND` / `Cannot find module '/app/src/data/templates.js'` (или другой файл во **вложенной** папке `data`).
- В GitHub файл на месте; в файл-менеджере бота папки `src/data/` может не быть.

### Причина

На нодах с bind mount агент копирует код репозитория на хост и **не перезаписывает** корневой `/app/data` (персистентный volume). Раньше использовался `ignore_patterns('data')`, который пропускал **любую** папку с именем `data` на любой глубине — в том числе исходники `src/data/`, `lib/data/` и т.п.

Это **не** кейс с `dist/` и **не** неверный entrypoint.

### Решение

1. Обновить агент на ноде (фикс: игнорируется только корневой `data/`).
2. Сделать **новый деплой** бота (одного рестарта мало — код на хосте нужно перекопировать).

Временный обходной путь без обновления агента: переименовать вложенную папку (например `src/data` → `src/datasets`) и поправить импорты.

---

## Ошибка: `Cannot find module '/app/index.js'` (код во вложенной папке)

### Симптомы

- Сборка образа проходит успешно (`Successfully built`).
- В **логах работы** при старте:

```text
Error: Cannot find module '/app/index.js'
code: 'MODULE_NOT_FOUND'
```

- Статус контейнера: `restarting`.
- В файл-менеджере бота в корне видны `package.json` и подпапка с кодом, но **нет** `index.js` в корне `/app`.

### Как отличить от ошибки с `dist/`

| Критерий | Этот кейс | Кейс с `dist/` выше |
|----------|-----------|---------------------|
| Путь в ошибке | `/app/index.js`, `/app/main.js` и т.п. (исходник) | `/app/dist/...`, `/app/build/...` |
| Файл в Git | **Нет** в корне репозитория | Обычно есть после `npm run build` в образе, но нет в Git |
| Причина | Неверный entrypoint / nested-структура | Bind mount затирает артефакты сборки |
| Фикс | Указать правильный путь к файлу | `WORKDIR` вне `/app` |

### Причина

Агент Bothost (и автогенерация Dockerfile) читает **корневой** `package.json` и запускает то, что указано в `main` / `scripts.start` (часто `node index.js`).

Если репозиторий устроен так:

```text
repo/
├── package.json          ← "main": "index.js", "start": "node index.js"
├── README.md
└── my-bot/               ← весь код здесь
    ├── index.js
    ├── package.json
    └── ...
```

то в корне **нет** `index.js`, а контейнер всё равно стартует с `CMD ["node", "index.js"]` → `Cannot find module '/app/index.js'`.

Типичный пример: [FuF1iK/botds](https://github.com/FuF1iK/botds) — код в `discord-html-watcher/`, а корневой `package.json` ссылается на несуществующий корневой `index.js`.

Это **не** связано с bind mount и `WORKDIR`: файла просто никогда не было по пути, который указан в команде запуска.

### Решение

Выберите один из вариантов.

#### 1. Указать main file при деплое (быстрее всего)

В форме создания бота откройте **«Дополнительные настройки»** и в поле **«Главный файл (точка входа)»** укажите путь от корня репозитория, например `discord-html-watcher/index.js` (или `subdir/index.js` / `bot/main.js` для своего репо).

![Поле «Главный файл» с путём discord-html-watcher/index.js](/docs/images/main-file-nested-entry.png)

*Пример: для репозитория [FuF1iK/botds](https://github.com/FuF1iK/botds) в поле указан `discord-html-watcher/index.js`.*

Полная инструкция по полю и автодетекту: [Главный файл (точка входа)](main-file-entrypoint).

#### 2. Исправить корневой `package.json`

```json
{
  "main": "discord-html-watcher/index.js",
  "scripts": {
    "start": "node discord-html-watcher/index.js"
  }
}
```

(подставьте свою папку). После правки — новый деплой.

#### 3. Вынести код в корень репозитория

Переложите файлы бота из подпапки в корень Git, чтобы entrypoint оказался сразу в `/app`.

**Было:**

```text
repo/
├── package.json              ← ссылается на несуществующий index.js
└── discord-html-watcher/
    ├── index.js
    ├── package.json
    └── ...
```

**Стало:**

```text
repo/
├── index.js                  ← точка входа в корне
├── package.json              ← "main": "index.js", "start": "node index.js"
└── ...
```

Тогда стандартный автодетект Bothost (`node index.js`) сработает без поля «Главный файл» и без правок путей. После переноса сделайте новый деплой.

### Дополнительно проверить

- В корневом `package.json` поля `main` и `scripts.start` указывают на файл, который **реально есть** в репозитории (проверьте пути в GitHub).
- Если в корне «лишний» `package.json` (копия или заглушка), а рабочий проект только во вложенной папке — либо поправьте пути, либо уберите корневой файл и укажите main file вручную.
- После смены entrypoint нужен **новый деплой**, одного рестарта контейнера недостаточно, если образ/команда запуска уже зафиксированы со старым путём.

---

## Ошибка: нет `node_modules` при кастомном Dockerfile (Node.js)

### Симптомы

- `Error: Cannot find module 'express'` (или другой пакет из `package.json`).
- Сборка образа прошла, зависимости ставились в `RUN npm ci`.

### Причина

Та же модель, что и с `dist/`: при монтировании `/app` с хоста локальный `node_modules` из образа в `/app` не виден. Bothost пытается скопировать `node_modules` из образа на хост при деплое; если структура проекта нестандартная (`WORKDIR` не `/app` при сборке), копирование может не совпасть с путём запуска.

### Решение

- Используйте `WORKDIR` вне `/app` для запуска **или** убедитесь, что `npm ci` в Dockerfile и `CMD` согласованы с тем, откуда реально стартует `node`.
- Не полагайтесь на `node_modules` в Git — только в образе/на хосте после деплоя.

---

## Ошибка: Go/Rust/Java бот — сборка успешна, контейнер сразу падает, логов нет

### Симптомы

- Все шаги `docker build` завершились успешно, образ создан.
- Сразу после `==> Build completed` бот в статусе `error` / `failed`.
- В логах сборки нет вывода от самого приложения — только сообщение агента
  «Контейнер упал сразу после запуска».
- Runtime-логи (`docker logs`) пусты или содержат:
  ```
  exec /app/bot: no such file or directory
  ```
- В файл-менеджере бота видны исходники (`main.go`, `go.mod`, …), но нет бинарника.

### Причина

На Bothost каталог `/app` при запуске контейнера монтируется с исходниками бота из Git (bind mount).
Это нужно для файлового менеджера и горячего обновления кода. Для интерпретируемых языков
(Python, Node.js) всё работает: исходник и есть запускаемый файл. Для компилируемых языков
(Go, Rust, Java) бинарник/JAR **живёт в слое образа**, а bind mount его скрывает.

```
/app/bot        ← скрыт bind mount'ом
/app/server     ← тоже скрыт
/app/bin/server ← тоже скрыт (весь /app перекрыт)
```

### Решение

Положите скомпилированный артефакт **вне `/app`** — например в `/usr/local/bin/`.

**Было (падает):**

```dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY . .
RUN go build -o /app/bot .

FROM alpine:3.20
WORKDIR /app
COPY --from=builder /app/bot .     # ← скрыт bind mount'ом
CMD ["./bot"]                      # ← не найден
```

**Стало (работает):**

```dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY . .
RUN go build -o /usr/local/bin/bot .

FROM alpine:3.20
WORKDIR /app
COPY --from=builder /usr/local/bin/bot /usr/local/bin/bot   # ← вне /app
RUN mkdir -p /app/data && chmod 777 /app/data
CMD ["/usr/local/bin/bot"]                                   # ← работает
```

Данные (БД, файлы) по-прежнему хранятся в `/app/data` — bind mount их видит
и сохраняет между деплоями.

### Примечание: кастомный Dockerfile vs автогенерация

Если у вас в репозитории **нет своего `Dockerfile`**, агент Bothost генерирует его
автоматически — и уже кладёт бинарник в `/usr/local/bin/` корректно.
Проблема возникает только при использовании **кастомного Dockerfile** из репозитория
со старой схемой (`COPY ... /app/`).

Самый быстрый способ исправить: снять галку «Использовать Dockerfile из репозитория»
при деплое, тогда агент сгенерирует правильный вариант сам.

### Совместимость языков с bind mount на `/app`

| Язык | Работает без изменений | Комментарий |
|---|---|---|
| Python | ✅ | Исходник запускается напрямую |
| Node.js | ✅ | То же (артефакты `dist/` — отдельный кейс выше) |
| PHP | ✅ | Исходник запускается напрямую |
| Go | ❌ | Бинарник должен быть в `/usr/local/bin/` |
| Rust | ❌ | То же |
| Java / Kotlin | ❌ | JAR должен быть вне `/app` |

---

## Контейнер в статусе `restarting`

### Симптомы

Бот не отвечает, в панели статус `restarting`, в логах одна и та же ошибка повторяется.

### Частые причины

1. Процесс сразу завершается с ошибкой (`MODULE_NOT_FOUND`, синтаксис, отсутствие env).
2. `CMD` запускает не тот файл или одноразовый скрипт вместо долгоживущего процесса (в т.ч. код во вложенной папке — см. раздел про `/app/index.js` выше).
3. Приложение слушает `127.0.0.1` вместо `0.0.0.0` (для вебхуков/домена).
4. Не заданы обязательные переменные (`BOT_TOKEN`, `GEMINI_API_KEY` и т.д.).

### Что делать

1. Откройте **логи работы** (не сборки).
2. Найдите **первую** ошибку в цикле перезапуска.
3. Сопоставьте с разделами этой статьи или [Кастомный Dockerfile](custom-dockerfile).

---

## Не работает DeepSeek / Gemini / OpenAI / Claude (ошибки API, timeout, geo)

### Симптомы

Бот запущен, но запросы к нейросетям и зарубежным API падают: timeout, connection error, geo/region blocked, «хостинг блокирует исходящие запросы».

### Причина

Bothost **не блокирует** исходящий трафик. У части нод IP определяется как российский, и внешний API (DeepSeek, Gemini, OpenAI, Claude и др.) отклоняет запросы.

### Решение

1. В [профиле](https://bothost.ru/profile.php) включите **«Зарубежный IP для API и нейросетей»**.
2. Задеплойте бота **заново** — существующие боты сами не переезжают на ноду с зарубежным IP.

Подробнее и скриншот: [FAQ — нейросети и зарубежные API](faq#foreign-ip-api).

---

## Сборка успешна, но 502 / 504 на домене

### Симптомы

Образ собран, контейнер `running`, сайт или webhook недоступны.

### Причина

Приложение не слушает нужный порт или интерфейс.

### Решение

- Слушать `0.0.0.0`, порт из переменной `PORT` (Bothost передаёт её в контейнер).
- Внутренний порт в настройках бота = порту в коде / `EXPOSE`.
- Подробнее: [Работа с доменами и портами](domains-and-ports), [Веб-приложения и домены](web-apps-domains).

---

## Ошибка: лог сборки обрывается после «Cloning into...»

### Симптомы

- В логах сборки видно только:

```text
==> Cloning https://github.com/...
Cloning into '...'...
```
- После этого поток обрывается, статус бота переходит в `failed`.
- Никакого сообщения об ошибке не отображается.

### Причина

Клонирование прошло успешно, но на следующем шаге чтения `Dockerfile` произошла ошибка. Чаще всего — `Dockerfile` сохранён в кодировке, отличной от UTF-8 (например, Windows-1251). Агент не смог прочитать файл и завершился без вывода в лог.

### Решение

1. Пересохраните `Dockerfile` в кодировке **UTF-8** (в VS Code: строка состояния снизу → кликнуть на кодировку → «Save with Encoding» → UTF-8).
2. Уберите кириллические комментарии из `Dockerfile` или переведите их на английский.
3. Запустите деплой повторно.

### Проверка кодировки

```bash
file Dockerfile
# OK:    ASCII text или UTF-8 Unicode text
# Плохо: ISO-8859, windows-1251, UTF-8 Unicode (with BOM)
```

---

## Ошибки только в логах сборки

| Сообщение | Возможная причина |
|-----------|-------------------|
| `npm ci` failed | Нет `package-lock.json`, несовместимые версии Node |
| `go build` failed | Неверный модуль, CGO, отсутствие файлов в `COPY` |
| `pip install` failed | Ошибка в `requirements.txt`, нужны системные пакеты (`apk`/`apt` в Dockerfile) |
| `COPY failed` | Файл в `.dockerignore`, пустой контекст |

Исправляйте `Dockerfile` и зависимости; runtime-логи здесь не помогут, пока образ не соберётся.

---

## Чеклист для кастомного Dockerfile (Node.js + сборка)

- [ ] `WORKDIR` для кода и `dist/` **не** `/app` (например `/usr/src/app`).
- [ ] Данные и БД — в `/app/data` или через `DATA_DIR`.
- [ ] `CMD` указывает на файл, который реально появляется после `npm run build`.
- [ ] Порт из `process.env.PORT`, хост `0.0.0.0` (если есть HTTP).
- [ ] Секреты — в переменных окружения Bothost, не в образе.
- [ ] После правок — новый деплой; проверены **и** логи сборки, **и** логи работы.

---

## См. также

- [Кастомный Dockerfile](custom-dockerfile)
- [Хранение базы данных](database-storage)
- [Переменные окружения](environment-variables)
- [FAQ](faq)

**Не нашли ответ?** [Поддержка](https://t.me/bothostru) или тикет в панели Bothost.
