Files
obsidian-vault/personal/tech/jellyfin-db-schema-mismatch.md
T

130 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Jellyfin: сервер старше БД — `no such column: p.Permission_Permissions_Guid`
> **Обнаружено:** 2026-09-20 на Kraken (RPi5/OMV, arm64, Docker).
> **Статус:** ✅ **ЗАФИКСИРОВАНО 2026-09-20** — контейнер пересоздан на образе 12.1.0.0, jellyfin `healthy`, Alex подтвердил «Заработало». См. раздел «Результат» ниже.
> **Симптом:** `jellyfin` не подключается (`http://kraken:8096` → **503**), контейнер `Up` но `unhealthy`, health-check бесконечно пишет `Server is could not complete startup. Check logs.`
> **Связанные:** [[personal/tech/docker-data-root-mount-race]], [[family/how-to/kraken-access]], [[family/plans/kraken-backup-to-truenas]]
## Суть (коротко)
**БД `jellyfin.db` мигрирована под Jellyfin 12.1.0.0, а запущенный контейнер работает на образе 10.11.8.**
Сервер 10.11.8 ожидает старую схему таблицы `Permissions` (с колонкой `Permission_Permissions_Guid`), а в 12.x-схеме её больше нет → падение на конструкторе `UserManager` → сервер не стартует.
Это **не** «миграция не прошла». Наоборот: миграции применены **вперёд**, а сервер откатился **назад**.
## Диагностика (воспроизводимая)
```bash
# 1) внешний симптом
ssh kraken 'docker exec jellyfin sh -c "curl -s -o /dev/null -w \"%{http_code}\n\" http://localhost:8096/"'
# → 503
# 2) статус
ssh kraken 'docker ps --format "{{.Names}} {{.Status}}" | grep jelly'
# → jellyfin Up ... (unhealthy)
# 3) ГДЕ ЛОГ: jellyfin пишет в ФАЙЛ, не в stdout!
# docker logs пуст по свежему запуску — не путаться.
ssh kraken 'sudo docker exec jellyfin sh -c "ls -lat /config/log/"'
ssh kraken 'sudo docker exec jellyfin sh -c "grep -nE \"SqliteException|could not complete startup\" /config/log/log_20260920.log | head"'
# → SQLite Error 1: 'no such column: p.Permission_Permissions_Guid'
# 4) какая версия сервера РЕАЛЬНО запущена
ssh kraken 'docker exec jellyfin sh -c "/jellyfin/jellyfin --version"'
# → Jellyfin.Server 10.11.8.0
# 5) какой образ у контейнера vs локальный latest
ssh kraken 'docker inspect jellyfin --format "{{.Image}}"'
ssh kraken 'docker inspect jellyfin/jellyfin:latest --format "{{.Id}}"'
# → РАЗНЫЕ ID
# 6) до какой версии мигрирована БД (на Mac, копия БД)
# см. скрипт ниже: миграции по ProductVersion
```
### Разбор БД (скопировать на Mac, не трогая оригинал)
```bash
ssh kraken 'sudo docker cp jellyfin:/config/data/jellyfin.db /tmp/jf.db && sudo chmod 644 /tmp/jf.db'
scp kraken:/tmp/jf.db /Users/admin/kraken-recovery/jellyfin-db/jellyfin.db
# затем python3: SELECT ProductVersion, COUNT(*) FROM __EFMigrationsHistory GROUP BY ProductVersion
# скрипт-разбор: /Users/admin/kraken-recovery/inspect_db.py, inspect_db2.py
```
## Факты инцидента (2026-09-20)
| Что | Значение |
|---|---|
| Образ **контейнера** | `sha256:1694ff06...` = **10.11.8** |
| Образ **локальный `latest`** | `sha256:78d3ea12...` = **12.1.0.0** (обновлён 15.09) |
| БД `jellyfin.db` мигрирована до | **12.1.0.0** (последняя миграция `20260911120000_StripEmbeddedLinkedChildren`) |
| Миграций в `__EFMigrationsHistory` | 105 (наборы: 9.0.11 ×36, 10.0.11 ×19, 10.11.8 ×32, 12.0.0 ×15, 12.1.0 ×3) |
| Схема `Permissions` в БД | **без** `Permission_Permissions_Guid` (12.x-форма) |
| Контейнер создан | 26.05.2026, **не пересоздавался** |
| Первое падение в логе | **09:57 (до shutdown Kraken)** — дефект не от перезагрузки |
| `SQLiteBackups/` (авто-бэкапы) | **пуст** |
| Единственный бэкап БД | `jellyfin.db.backup-20260617_034429` (17.06) |
## Как это получилось
`latest` указывал на 10.11.8 в мае → контейнер создан на этом образе. 15.09 `latest` на Hub обновился до **12.1**. Контейнер в какой-то момент запустился на новом образе (или compose пересоздал его), миграции прошли до 12.1.0.0. Затем контейнер вернулся на **старый** образ 10.11.8 (снапшот от 26.05) — и уже не может стартовать с новой БД.
**Питфолл тега `latest`:** `docker inspect` показывает digest, откуда образ БЫЛ СКАЧАН, а не текущий `latest`. Локальный «latest» может быть сильно старше, чем `latest` в реестре. Проверять версию **внутри образа**: `docker run --rm --entrypoint sh jellyfin/jellyfin:latest -c '/jellyfin/jellyfin --version'`.
## Фикс (ВЫПОЛНЕН 2026-09-20)
**Миграцию вручную запустить НЕЛЬЗЯ и не нужно** — миграции уже применены (до 12.1.0.0), запускать нечего; даунгрейд схемы EF Core не поддерживает. Проблема не в БД, а в **образе контейнера**.
```bash
# 1) БЭКАП БД (авто-бэкапов нет!)
ssh kraken 'D=/home/kraken/backups/jellyfin-db-$(date +%Y%m%d-%H%M%S); mkdir -p $D; \
sudo docker cp jellyfin:/config/data/jellyfin.db $D/ && \
sudo docker cp jellyfin:/config/data/jellyfin.db-wal $D/ 2>/dev/null; \
sudo chown -R kraken:kraken $D; ls -la $D'
# 2) пересоздать контейнер на актуальном образе
ssh kraken 'cd /srv/dev-disk-by-uuid-6194539b-03e0-4f33-986b-4da09834e82f/docker/jellyfin && \
sudo docker compose up -d --force-recreate'
# 3) проверка
ssh kraken 'docker exec jellyfin sh -c "/jellyfin/jellyfin --version"' # ожидаем 12.1.0.0
ssh kraken 'docker ps --format "{{.Names}} {{.Status}}" | grep jelly' # health: healthy
ssh kraken 'docker exec jellyfin sh -c "curl -s -o /dev/null -w \"%{http_code}\n\" http://localhost:8096/"'
```
**Риск:** низкий. Данные (`/config`) не трогаются, пересоздаётся только контейнер. Бэкап БД обязателен — откатываться больше некуда.
## ✅ Результат (2026-09-20)
| Шаг | Факт |
|---|---|
| Бэкап БД | `/home/kraken/backups/jellyfin-recreate-20260920-165750/` — `jellyfin.db` (24.5 МБ) + `-wal` + `-shm` |
| Пересоздание | `docker compose up -d --force-recreate` → `Container jellyfin Recreated / Started`, rc=0 |
| Статус через 15 с | **`Up 15 seconds (healthy)`** — сразу healthy, без периода `starting` |
| Подтверждение Alex | «Заработало» |
> Контейнер теперь работает на образе `jellyfin/jellyfin:latest` = **12.1.0.0**, что согласовано с версией БД. Проблема `no such column` закрыта.
**Compose jellyfin** (`/srv/.../docker/jellyfin/docker-compose.yml`):
```yaml
image: jellyfin/jellyfin # без тега = latest
restart: always
ports: ["8096:8096"]
volumes:
- /srv/.../docker/jellyfin:/config
- /srv/.../media:/media:ro
environment: [TZ=Asia/Almaty]
```
> Рекомендация на будущее: **пинить тег** (`jellyfin/jellyfin:12.1`) вместо `latest`, иначе `watchtower` может снова переключить мажорную версию и сломать БД.
## Питфоллы диагностики
- **`docker logs jellyfin` не показывает свежий старт** — jellyfin пишет в `/config/log/log_YYYYMMDD.log`, а не в stdout. Читать файл внутри контейнера.
- **В контейнере нет `sqlite3`, `python3`, `strings`** — БД разбирать только копией на Mac.
- **Старые ошибки в логе сбивают**: `System.UriFormatException: Invalid URI` и `WS ... closed` — это НЕ причина падения, а фон. Искать `SqliteException` и `could not complete startup`.
- Проверять **`--since`** фильтр осторожно: если контейнер старше, `--since 15m` даст пусто.
## Урок
При `no such column` в jellyfin (или любом EF Core сервисе) **первым делом сравнивать версию бинарника внутри запущенного контейнера с максимальной версией в `__EFMigrationsHistory`**. Версия БД выше версии сервера = откатился образ. Лечится пересозданием контейнера на правильном образе, НЕ правкой БД.