# Справочник ошибок при деплое Все типичные ошибки на 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).
  • В логах работы при старте:
Error: Cannot find module '/app/dist/server.cjs'
code: 'MODULE_NOT_FOUND'
  • Статус контейнера: restarting (циклический перезапуск).

Причина

На Bothost при деплое с кастомным Dockerfile возможна такая схема:
    • При сборке образа в WORKDIR /app выполняется npm run build → в образе появляется /app/dist/....
    • При запуске контейнера на части серверов каталог /app монтируется с хоста: туда попадает исходный код из Git, без папки dist/ (её обычно нет в репозитории и в .gitignore).
    • Команда CMD ["node", "dist/server.cjs"] ищет файл в примонтированном /app, а не в слое образа → MODULE_NOT_FOUND.
Типичный кейс: Node.js/TypeScript проект с esbuild/tsc, WORKDIR /app, DATA_DIR=/app/data, как в Negodiay-Bot. Платформа отдельно восстанавливает из образа на хост node_modules (для Node.js), но не каталоги вроде dist/, build/, .next/ — их нужно либо не класть в /app, либо собирать при каждом старте.

Решение

Перенесите код приложения и артефакты сборки вне /app. Каталог /app/data оставьте для персистентных данных (БД, загрузки) — он как раз предназначен для volume. Было (проблемный вариант):
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"]
Стало (рекомендуется):
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 (хранение БД).

Дополнительно проверить

  • В коде пути к данным берутся из 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.

Решение

    • Обновить агент на ноде (фикс: игнорируется только корневой data/).
    • Сделать новый деплой бота (одного рестарта мало — код на хосте нужно перекопировать).
Временный обходной путь без обновления агента: переименовать вложенную папку (например src/datasrc/datasets) и поправить импорты.

Ошибка: Cannot find module '/app/index.js' (код во вложенной папке)

Симптомы

  • Сборка образа проходит успешно (Successfully built).
  • В логах работы при старте:
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). Если репозиторий устроен так:
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 — код в 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
Пример: для репозитория FuF1iK/botds в поле указан discord-html-watcher/index.js.
Полная инструкция по полю и автодетекту: Главный файл (точка входа).

2. Исправить корневой package.json

{
  "main": "discord-html-watcher/index.js",
  "scripts": {
    "start": "node discord-html-watcher/index.js"
  }
}
(подставьте свою папку). После правки — новый деплой.

3. Вынести код в корень репозитория

Переложите файлы бота из подпапки в корень Git, чтобы entrypoint оказался сразу в /app. Было:
repo/
├── package.json              ← ссылается на несуществующий index.js
└── discord-html-watcher/
    ├── index.js
    ├── package.json
    └── ...
Стало:
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/. Было (падает):
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"]                      # ← не найден
Стало (работает):
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 / KotlinJAR должен быть вне /app
---

Контейнер в статусе restarting

Симптомы

Бот не отвечает, в панели статус restarting, в логах одна и та же ошибка повторяется.

Частые причины

    • Процесс сразу завершается с ошибкой (MODULE_NOT_FOUND, синтаксис, отсутствие env).
    • CMD запускает не тот файл или одноразовый скрипт вместо долгоживущего процесса (в т.ч. код во вложенной папке — см. раздел про /app/index.js выше).
    • Приложение слушает 127.0.0.1 вместо 0.0.0.0 (для вебхуков/домена).
    • Не заданы обязательные переменные (BOT_TOKEN, GEMINI_API_KEY и т.д.).

Что делать

    • Откройте логи работы (не сборки).
    • Найдите первую ошибку в цикле перезапуска.
    • Сопоставьте с разделами этой статьи или Кастомный Dockerfile.

Не работает DeepSeek / Gemini / OpenAI / Claude (ошибки API, timeout, geo)

Симптомы

Бот запущен, но запросы к нейросетям и зарубежным API падают: timeout, connection error, geo/region blocked, «хостинг блокирует исходящие запросы».

Причина

Bothost не блокирует исходящий трафик. У части нод IP определяется как российский, и внешний API (DeepSeek, Gemini, OpenAI, Claude и др.) отклоняет запросы.

Решение

    • В профиле включите «Зарубежный IP для API и нейросетей».
    • Задеплойте бота заново — существующие боты сами не переезжают на ноду с зарубежным IP.
Подробнее и скриншот: FAQ — нейросети и зарубежные API.

Сборка успешна, но 502 / 504 на домене

Симптомы

Образ собран, контейнер running, сайт или webhook недоступны.

Причина

Приложение не слушает нужный порт или интерфейс.

Решение


Ошибка: лог сборки обрывается после «Cloning into...»

Симптомы

  • В логах сборки видно только:
==> Cloning https://github.com/...
Cloning into '...'...
  • После этого поток обрывается, статус бота переходит в failed.
  • Никакого сообщения об ошибке не отображается.

Причина

Клонирование прошло успешно, но на следующем шаге чтения Dockerfile произошла ошибка. Чаще всего — Dockerfile сохранён в кодировке, отличной от UTF-8 (например, Windows-1251). Агент не смог прочитать файл и завершился без вывода в лог.

Решение

    • Пересохраните Dockerfile в кодировке UTF-8 (в VS Code: строка состояния снизу → кликнуть на кодировку → «Save with Encoding» → UTF-8).
    • Уберите кириллические комментарии из Dockerfile или переведите их на английский.
    • Запустите деплой повторно.

Проверка кодировки

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, не в образе.
  • [ ] После правок — новый деплой; проверены и логи сборки, и логи работы.

См. также

Не нашли ответ? Поддержка или тикет в панели Bothost.