Разбор типичных проблем
Оглавление · Далее: ограничения
Сначала определите слой: файл/сборка, web, CMS, очередь, worker, сеть или VPS.
Проверяйте конкретный симптом одной командой, а не удаляйте базы «на всякий случай».
Production-команды dc используют оболочку из эксплуатации.
Установка, сборка и dev
| Симптом | Проверка | Причина и действие |
|---|---|---|
| Docker Client есть, Server недоступен | docker version | Запустить Docker daemon; проверить context |
Cannot find @gheilt/contracts/dist | pnpm --filter @gheilt/contracts build | Contracts ещё не собран; root dev делает это автоматически |
| Изменение contracts не видно | Проверить dist и перезапустить потребителя | Watch воркера не заменяет watch-сборку соседнего пакета |
Неизвестны PageProps/LayoutProps | pnpm --filter @gheilt/web typecheck | Нужен next typegen |
| Node не понимает syntax/alias | node --version, импорт | Native TS не применяет Next aliases и весь TS-синтаксис |
| Порт уже занят | Остановить свой предыдущий dev-процесс или выбрать другой порт | Не завершать посторонний процесс без определения владельца |
| npm пишет EPERM в cache | Проверить свой npm cache path | Использовать доступный npm --cache /tmp/gheilt-npm-cache ...; не менять владельцев всего HOME |
Warning о next start и standalone | Проверить output: standalone | Production запускается Docker CMD, не root pnpm start |
Локальный pnpm start сохранён в scripts, но Next предупреждает о standalone.
Для production-проверки рекомендуются готовый Docker-образ и Compose. Если вручную
запускаете standalone, нужны корректно доставленные .next/static и public.
Docker и PostgreSQL
| Симптом | Проверка | Действие |
|---|---|---|
unsupported tag !reset | docker compose version | Обновить Compose, не удалять поля override вслепую |
${...:?Run pnpm setup} | Наличие .env без вывода его содержимого | Выполнить setup для новой локальной среды |
| PG authentication failed | Сравнить факт смены .env и возраст volume | Existing DB password не меняется от редактирования env |
| Init script не создаёт новую роль | Data volume уже существует | Нужна явная миграция, а не повторный up |
cms.localhost не открывается | curl с --resolve | Проверить DNS/hosts и Host-routing Caddy |
| HTML есть, картинок/robots нет | HTTP-запрос к ресурсу, Dockerfile COPY | Проверить public/static в runtime-образе |
| Container running, сервис не работает | logs, endpoint, реальное действие | Running и HTTP health не равны бизнес-readiness |
Webhook
| Ответ/симптом | Значение | Что проверить |
|---|---|---|
| 401 | Authorization не совпал | Bearer prefix, secret CMS и web, env после пересоздания |
| 400 | JSON/контракт неверен | event enum, model, entry, тело действительно JSON |
| 503 not configured | Нет webhook secret | shared env и environment web |
| 503 cache invalidation unavailable | Не удалось сбросить кеш Next.js | Логи web, настройки кеша и runtime Next.js |
| 200, сайт не изменился | Кеш истёк; HTML обновляется при посещении | Откройте страницу заново; проверьте Publish, URL webhook и CMS response |
Для разбора payload используйте очищенную копию. Не публикуйте Authorization header.
Strapi-контейнер должен отправлять запрос на web:3000, не на свой localhost.
Hatchet: новая база, tenant и token
На новой локальной базе выполните seed до pnpm infra:token:
docker compose exec -T hatchet /hatchet-admin seed --config /config
Ошибка APIToken_tenantId_fkey при создании токена означает, что CLI пытается
сослаться на отсутствующий tenant. Возможны новая база без seed или нестандартный
tenant. Не выбирайте автоматически первый tenant, если это internal.
В production create-worker-token.py:
- seed-ит обычного администратора/tenant;
- исключает slug
internal; - получает ID обычного tenant;
- проверяет
subтекущего токена и создаёт новый при несовпадении.
При нескольких обычных tenants script выбирает самый ранний. Это ограничение учебной схемы, не интерфейс управления multi-tenant системой.
Если seed не создаёт администратора, проверьте сложность ADMIN_PASSWORD.
Production генератор использует случайное значение с uppercase/lowercase/digit.
Смена initial password после первого seed не обновляет уже созданный аккаунт.
Если task не выполняется после пересоздания PostgreSQL, проверяйте логи Hatchet:
HTTP-панель могла пережить потерю queue connections. restart: true зависимостей
помогает при управляемом Compose-обновлении; отдельный ручной restart через docker
не обязан повторять тот же порядок. Восстановление очереди проверяйте новым тестовым
событием, а не только наличием старого сообщения.
Истёкший токен и неверный адрес
Стандартный CLI-token живёт 90 дней. Наличие непустой строки в .env не означает,
что token действителен. Production helper не обновляет токен только по exp.
На компьютере gRPC — 127.0.0.1:7070, в контейнере — hatchet:7070.
URL HTTP-панели и gRPC host:port — разные настройки. Внутренний SDK идёт
напрямую к сервису внутри сети.
VPS и CI
| Симптом | Проверка | Действие |
|---|---|---|
| Deploy skipped | VPS_READY, ref/event | Разрешить deploy только после подготовки хоста |
| SSH Permission denied | User gheilt-deploy, dedicated key, authorized_keys | Не пробовать root/personal key в workflow |
| Host key verification failed | Изменение host key и known_hosts | Подтвердить новый fingerprint через доверенный канал |
| GHCR pull denied | Packages permission и job token | Проверить job/repository access; не сохранять token в открытом файле |
| Архитектура образа неверна | uname -m, CI platforms | Workflow сейчас собирает linux/amd64 |
Another deployment is running | Кто держит deploy.lock | Дождаться владельца, не удалять lock-файл вместо освобождения fd |
| TLS/HTTPS health не проходит | DNS, 80/443, Caddy logs | Проверить домен и доступность ACME; не отключать проверку TLS |
| Rollback не помог | Совместимость базы и старой CMS | Image rollback не отменяет миграции |
| Диск заполнен | df -h, docker system df | Определить объекты; не удалять volumes глобальным prune |
Если лог GitHub CLI не сохраняется из-за прав на local cache:
XDG_CACHE_HOME=/tmp/gheilt-cache gh run view <RUN_ID> --repo maderwin/gheilt --log-failed
Замените <RUN_ID> числом. Логи pipeline тоже нужно просмотреть на предмет
production-данных перед дальнейшей публикацией.
Минимальная последовательность расследования
- Назвать конкретную ожидаемую операцию и фактический результат.
- Проверить конфигурацию без печати секретов.
- Проверить ближайший к ошибке сервис и его логи.
- Воспроизвести на локальной среде с тестовыми данными.
- Исправить причину, проверить operation целиком и закоммитить этап.
Не превращайте историческое удачное выполнение в доказательство текущей исправности.
CMS, импорт и фотографии
- Контент временно недоступен: проверьте health Strapi, STRAPI_INTERNAL_URL, read-only token и опубликованный Site. Не выводите .env/headers в журнал и не добавляйте JSON fallback.
- 401/403: Content API token отличается от admin JWT. cms:token должен захватить marker без печати; POST с read-only token закономерно получает 403.
- После Publish нет записи: проверьте status=published, slug, publishedOn и Blocks contract; build не требуется. Причина может быть валидацией другой записи полного списка.
- Media 404: проверьте upload provider, Garage website allow и object prefix strapi/. Proxy принимает только filename и raster extension; SVG оригинального логотипа конвертируется.
- Media 503: HTTP ошибки, timeout, превышение 25 MiB или не-image MIME. Node fetch может игнорировать custom Host: здесь используется node:http с фиксированным Garage Host.
- Импорт failed: сначала исправьте причину и повторите тот же snapshot без update-existing. Каталог reuse сохраняет успешные uploads; импорт не удаляет прежние документы.
- CLI aborted при shutdown после publish: pinned Strapi onCommit callbacks не await-ятся самим framework. Используйте актуальный importer с track-transactions; не маскируйте ошибку exit 0 и повторите настоящее завершение CLI.
- Snapshot incomplete: сеть/частная подробная запись блокирует запись нового snapshot; старый атомарно сохранённый архив остаётся.
- CONTENT_READY=false: workflow подготовил CMS и оставил старый web; это ожидаемый переходный этап. Готовность устанавливается после полного explicit import и проверки.