A troubleshooting guide for Pangolin upgrades from 1.17.x → 1.18.x when the SQLite database schema is out of sync with the running application.
Tested fix path: seed versionMigrations with 1.17.0, then re-run migrations.
After upgrading Pangolin to 1.18.x (e.g. 1.18.4), the service may fail to start with errors like:
SqliteError: no such column: resources.health
Or, after partial manual fixes:
SqliteError: no such column: "networkId"
Migration logs may misleadingly show success:
Starting migrations from version 1.18.4
Migrations to run:
All migrations completed successfully
…while the database is still on the 1.17 schema.
Pangolin tracks applied migrations in the versionMigrations SQLite table. The migration runner uses the highest version in that table as the starting point:
- If
versionMigrationsis empty, it defaults to the current app version (e.g.1.18.4). - Nothing runs because no migration version is greater than
1.18.4. - The app code expects 1.18 columns (
resources.health,sites.networkId,networkstable, etc.) that were never created.
This commonly happens when:
versionMigrationswas wiped (e.g. Proxmox community-scripts update logic deletes all rows whenstatusHistoryis missing).- A partial upgrade left migration records at 1.18.x without completing the 1.18.0 schema changes.
- Manual SQL patches (adding individual columns) bypass the full 1.18.0 migration — each missing column causes the next error.
Do not fix this by adding columns one at a time. The 1.18.0 migration is large (new tables, recreated siteResources / targetHealthCheck, data migration, status history seeding).
- Proxmox LXC installs via community-scripts/ProxmoxVE (
/opt/pangolin,systemctl pangolin) - Docker installs (
config/db/db.sqlitemounted into the container) - Any local SQLite install using Pangolin's migration runner (
dist/migrations.mjs)
Adjust paths for your install:
| Install type | Database path |
|---|---|
| Proxmox LXC | /opt/pangolin/config/db/db.sqlite |
| Docker | ./config/db/db.sqlite (or your volume mount) |
DB="/opt/pangolin/config/db/db.sqlite" # change if needed
echo "=== versionMigrations ==="
sqlite3 "$DB" "SELECT version FROM versionMigrations ORDER BY version;"
echo "=== 1.18 columns ==="
sqlite3 "$DB" "PRAGMA table_info(resources);" | grep -E 'health|wildcard' || echo "MISSING: resources.health"
sqlite3 "$DB" "PRAGMA table_info(sites);" | grep networkId || echo "MISSING: sites.networkId"
echo "=== 1.18 tables ==="
sqlite3 "$DB" "SELECT name FROM sqlite_master WHERE type='table' AND name IN ('networks','statusHistory','alertRules');"Broken state looks like:
versionMigrationsis empty or only has1.18.xrows while columns/tables above are missing.- Logs show
Starting migrations from version 1.18.4with an emptyMigrations to run:line.
systemctl stop pangolin gerbil
DB="/opt/pangolin/config/db/db.sqlite"
cp "$DB" "/opt/pangolin/config/db/db.sqlite.backup-$(date +%Y%m%d-%H%M%S)"
# Remove any false 1.18 migration records
sqlite3 "$DB" "DELETE FROM versionMigrations WHERE version IN ('1.18.0','1.18.3','1.18.4');"
# If the table is empty, tell the migrator we are at 1.17.0
COUNT=$(sqlite3 "$DB" "SELECT COUNT(*) FROM versionMigrations;")
if [ "$COUNT" -eq 0 ]; then
sqlite3 "$DB" "INSERT INTO versionMigrations (version, executedAt) VALUES ('1.17.0', cast(strftime('%s','now') as integer) * 1000);"
fi
# Run migrations manually and watch output
cd /opt/pangolin
ENVIRONMENT=prod node dist/migrations.mjsExpected output:
Starting migrations from version 1.17.0
Migrations to run: 1.18.0, 1.18.3, 1.18.4
Running migration 1.18.0
...
Recomputed health for N resource(s)
Successfully completed migration 1.18.0
...
All migrations completed successfully
# Verify schema
sqlite3 "$DB" "PRAGMA table_info(resources);" | grep health
sqlite3 "$DB" "PRAGMA table_info(sites);" | grep networkId
sqlite3 "$DB" "SELECT version FROM versionMigrations ORDER BY version;"
systemctl start pangolin gerbil
journalctl -u pangolin -n 30 --no-pager
curl -sf http://localhost:3001/api/v1/ # should return {"message":"Healthy"}docker compose stop pangolin
DB="./config/db/db.sqlite"
cp "$DB" "./config/db/db.sqlite.backup-$(date +%Y%m%d-%H%M%S)"
sqlite3 "$DB" "DELETE FROM versionMigrations WHERE version IN ('1.18.0','1.18.3','1.18.4');"
COUNT=$(sqlite3 "$DB" "SELECT COUNT(*) FROM versionMigrations;")
if [ "$COUNT" -eq 0 ]; then
sqlite3 "$DB" "INSERT INTO versionMigrations (version, executedAt) VALUES ('1.17.0', cast(strftime('%s','now') as integer) * 1000);"
fi
docker compose run --rm pangolin node dist/migrations.mjs
# Or exec into the container with ENVIRONMENT=prod if your image supports it
docker compose up -d pangolin
docker logs pangolin 2>&1 | tail -30If migrations fail with "table already exists" or "duplicate column", the database is in a mixed state. Restore instead of patching.
Pangolin auto-backups before migrations:
config/db/backups/db_YYYY-MM-DD_*.sqlite
Proxmox update script may also create:
/opt/pangolin/config/db/db.sqlite.pre-1.18.4-*.bak
systemctl stop pangolin gerbil # or docker compose stop pangolin
cp config/db/backups/db_<pre-1.18-timestamp>.sqlite config/db/db.sqlite
cd /opt/pangolin && ENVIRONMENT=prod node dist/migrations.mjs
systemctl start pangolin gerbil| Don't | Why |
|---|---|
DELETE FROM versionMigrations; without re-inserting 1.17.0 |
Causes migrations to skip entirely |
Manually ALTER TABLE resources ADD health ... only |
Next error will be networkId, then more — 1.18.0 changes ~20+ schema items |
| Assume "All migrations completed successfully" means OK | Empty Migrations to run: with start version 1.18.4 means nothing ran |
| Upgrade from 1.18 RC → 1.18 release on same DB | Not supported; restore 1.17 backup first (issue #2925) |
-
versionMigrationscontains1.17.0,1.18.0,1.18.3,1.18.4 -
resources.healthcolumn exists -
sites.networkIdcolumn exists -
networksandstatusHistorytables exist - Pangolin starts without
SqliteErrorin logs - API health check returns
{"message":"Healthy"}(internal port 3001) - Dashboard loads; resource health checks display in UI
- fosrl/pangolin#2925 —
resources.healthafter RC → 1.18.0 upgrade - fosrl/pangolin#2938 — health checks after 1.18 migration; restore 1.17 backup + upgrade to 1.18.1+ recommended
- community-scripts/ProxmoxVE pangolin.sh — update script that may clear
versionMigrationswhenstatusHistoryis missing
Empty versionMigrations + Pangolin 1.18 app = skipped migrations. Insert 1.17.0, run node dist/migrations.mjs, verify resources.health exists, restart
start the service.
Contributions welcome — if you hit an edge case, please note your install method, Pangolin version, and migration log output in a comment or PR. ➜ ~