fix: exclude channel_database from migration 021 to prevent PostgreSQL boot-loop#3640
Conversation
…t PostgreSQL boot-loop PostgreSQL runs all migrations on every startup (no per-migration tracking). Migration 021 added sourceId to channel_database; migration 063 drops it. The ADD/DROP cycle each boot consumed a PostgreSQL pg_attribute tombstone slot. After ~1600 boots the table hit PostgreSQL's hard 1600-column limit, causing a crash on startup with "tables can have at most 1600 columns". Fix: remove channel_database from migration 021's DATA_TABLES array. Migration 063 already handles cleanup of any previously added sourceId column. channel_database is global-by-design (migration 063 explains why). Fixes: #3639 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cu5UZv6q58JhV62cWjM6KG
|
Claude finished @Yeraze's task —— View job PR Review
|
…3657) (#3658) * fix(migration): guard 033 channel_database backfill on column existence (#3657) Regression introduced by #3640 (v4.11.4): removing channel_database from migration 021's sourceId-add left migration 033's `UPDATE channel_database SET sourceId ...` referencing a column that no longer exists. On PostgreSQL — which re-runs every migration on every boot — and on fresh installs, 033 then crashed during DB init with `column "sourceId" does not exist`, so the app couldn't start. The crash only triggered when at least one source was registered (the backfill is gated on `sources.length > 0`); the CI fixtures have no sources, which is why it slipped through. Fix: guard the channel_database backfill on the legacy `sourceId` column still existing (PRAGMA table_info on SQLite, information_schema on PG/MySQL). channel_database is global-by-design (063 drops sourceId), so on current databases the column is absent and the backfill is correctly a no-op; on a mid-upgrade DB where the column is still present it still runs. Adds 033_per_source_permissions.test.ts: reproduces #3657 (source present + channel_database without sourceId → no throw), confirms back-compat backfill when the column is present, and the no-sources case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4 * release: v4.11.5 (hotfix for #3657) Bumps all five version files 4.11.4 -> 4.11.5. v4.11.4 was retracted because migration 033 crashed Postgres/fresh-install startup (#3657); this release carries the fix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4 --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Summary
Fixes #3639 — PostgreSQL users experiencing a boot-loop with
tables can have at most 1600 columnsafter many restarts.Root Cause
PostgreSQL runs all migrations on every startup (no per-migration tracking, unlike SQLite which uses
settingsKey). This is intentional — each migration is supposed to be idempotent viaIF NOT EXISTSguards.However, there's a dangerous interaction between two migrations:
sourceIdtochannel_databasewithADD COLUMN IF NOT EXISTSsourceIdfromchannel_databasewithDROP COLUMN IF EXISTSOn every boot, the cycle runs: add → drop → add → drop → …
PostgreSQL counts dropped column "tombstones" in
pg_attributetoward its hard 1600-column limit per table, and never reclaims those slots automatically. After ~1600 boots, anyALTER TABLE channel_database ADD COLUMNfails with the error the reporter sees.Fix
Remove
channel_databasefrom migration 021'sDATA_TABLESarray.channel_databaseis global-by-design —channelDecryptionServicequeries all rows regardless of source. Migration 063 already handles cleanup of anysourceIdthat was added by prior runs of migration 021 (DROP COLUMN IF EXISTSis a safe no-op if the column isn't there).The net result: migration 021 no longer touches
channel_database, the add/drop cycle stops, and the tombstone count stops growing.Impact on existing affected users
Users who have already hit the limit can simply update to this version and restart — migration 021 will no longer attempt
ADD COLUMNonchannel_database, so the 1600-column error won't fire. Their table will still have many dead tombstone slots, but since no migration adds further columns tochannel_database, this is harmless at runtime.🤖 Generated with Claude Code
https://claude.ai/code/session_01Cu5UZv6q58JhV62cWjM6KG
Generated by Claude Code