Учебное руководство
Главы руководства
На этой странице

Разбор типичных проблем

Оглавление · Далее: ограничения

Сначала определите слой: файл/сборка, web, CMS, очередь, worker, сеть или VPS. Проверяйте конкретный симптом одной командой, а не удаляйте базы «на всякий случай». Production-команды dc используют оболочку из эксплуатации.

Установка, сборка и dev

СимптомПроверкаПричина и действие
Docker Client есть, Server недоступенdocker versionЗапустить Docker daemon; проверить context
Cannot find @gheilt/contracts/distpnpm --filter @gheilt/contracts buildContracts ещё не собран; root dev делает это автоматически
Изменение contracts не видноПроверить dist и перезапустить потребителяWatch воркера не заменяет watch-сборку соседнего пакета
Неизвестны PageProps/LayoutPropspnpm --filter @gheilt/web typecheckНужен next typegen
Node не понимает syntax/aliasnode --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: standaloneProduction запускается Docker CMD, не root pnpm start

Локальный pnpm start сохранён в scripts, но Next предупреждает о standalone. Для production-проверки рекомендуются готовый Docker-образ и Compose. Если вручную запускаете standalone, нужны корректно доставленные .next/static и public.

Docker и PostgreSQL

СимптомПроверкаДействие
unsupported tag !resetdocker compose versionОбновить Compose, не удалять поля override вслепую
${...:?Run pnpm setup}Наличие .env без вывода его содержимогоВыполнить setup для новой локальной среды
PG authentication failedСравнить факт смены .env и возраст volumeExisting 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

Ответ/симптомЗначениеЧто проверить
401Authorization не совпалBearer prefix, secret CMS и web, env после пересоздания
400JSON/контракт неверенevent enum, model, entry, тело действительно JSON
503 not configuredНет webhook secretshared 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 skippedVPS_READY, ref/eventРазрешить deploy только после подготовки хоста
SSH Permission deniedUser gheilt-deploy, dedicated key, authorized_keysНе пробовать root/personal key в workflow
Host key verification failedИзменение host key и known_hostsПодтвердить новый fingerprint через доверенный канал
GHCR pull deniedPackages permission и job tokenПроверить job/repository access; не сохранять token в открытом файле
Архитектура образа невернаuname -m, CI platformsWorkflow сейчас собирает linux/amd64
Another deployment is runningКто держит deploy.lockДождаться владельца, не удалять lock-файл вместо освобождения fd
TLS/HTTPS health не проходитDNS, 80/443, Caddy logsПроверить домен и доступность ACME; не отключать проверку TLS
Rollback не помогСовместимость базы и старой CMSImage 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-данных перед дальнейшей публикацией.

Минимальная последовательность расследования

  1. Назвать конкретную ожидаемую операцию и фактический результат.
  2. Проверить конфигурацию без печати секретов.
  3. Проверить ближайший к ошибке сервис и его логи.
  4. Воспроизвести на локальной среде с тестовыми данными.
  5. Исправить причину, проверить 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 и проверки.