Skip to content

Fix SQLite startup crash dropping workspaces.package_manager on populated databases - #550

Open
jbouder wants to merge 2 commits into
mainfrom
fix/sqlite-drop-column-fk
Open

Fix SQLite startup crash dropping workspaces.package_manager on populated databases#550
jbouder wants to merge 2 commits into
mainfrom
fix/sqlite-drop-column-fk

Conversation

@jbouder

@jbouder jbouder commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Fixes #549

Problem

Since #522, every SQLite-backed nebi (desktop app and nebi serve) crashes on startup when migrating a database created before the package_manager removal that contains workspaces referenced by child rows (jobs, publications, …):

Error: failed to run migrations: failed to drop workspaces.package_manager column: constraint failed: FOREIGN KEY constraint failed (787)

The glebarez/sqlite driver emulates DropColumn by rebuilding the table (create workspaces__temp → copy rows → DROP TABLE workspaces → rename), and — unlike its DropTable/AlterColumn paths — does not suspend foreign_keys first. With nebi's DSN-level _pragma=foreign_keys(ON), the DROP TABLE on the parent violates the foreign keys held by referencing rows and aborts startup. The rebuild runs inside a single transaction, so the failure rolls back cleanly — the database is left intact but cannot boot, and the crash recurs on every startup.

Postgres is unaffected (DropColumn is a native ALTER TABLE ... DROP COLUMN there).

Fix

  • Run the package_manager drop pinned to a single connection (db.Connection) with PRAGMA foreign_keys = OFF/ON around it. Pinning is required because the DSN pragma re-enables enforcement on every new pooled connection, and the pragma must be flipped outside the rebuild's transaction, where SQLite ignores it.
  • Keep the plain native drop on Postgres.

An earlier revision of this PR also dropped a "stranded" workspaces__temp table at startup, on the theory that failed attempts leave the rebuild's temp table behind. That premise was wrong — the rebuild is transactional and rolls the temp table back on failure (verified empirically and against a real post-crash database) — so that cleanup has been removed.

Testing

  • New TestMigrateDropsLegacyPackageManagerColumnWithReferencingRows reproduces the crash scenario: legacy schema with the NOT NULL column and a jobs row holding an FK to a workspace. It verifies the migration succeeds, the column is gone, and all rows survive.
  • Verified end-to-end against a real pre-Remove uv and the package-manager abstraction; pixi is the only package manager #522 nebi.db (legacy column + referencing job rows): nebi serve previously crashed, now boots cleanly with data intact.
  • go test ./internal/db/, go build ./internal/..., go vet, gofmt all clean.

🤖 Generated with Claude Code

…ated databases

The glebarez/sqlite driver emulates DropColumn by rebuilding the table
(create workspaces__temp, copy rows, drop workspaces, rename), and
unlike DropTable/AlterColumn it does not suspend foreign_keys first, so
DROP TABLE on the old workspaces violates the foreign keys held by
jobs/publications rows and aborts startup on any pre-#522 database with
real usage history.

Run the drop pinned to a single connection with foreign_keys suspended
(the DSN pragma re-enables it on every new pooled connection, and
SQLite ignores the pragma inside a transaction), and drop any
workspaces__temp table stranded by a previously failed rebuild before
AutoMigrate runs.

Fixes #549

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jbouder
jbouder marked this pull request as draft August 28, 2026 16:20
The driver's DropColumn rebuild (create temp, copy, drop, rename) runs
inside a single transaction, so the pre-fix FK failure rolls the temp
table back — a committed database can never contain a stranded
workspaces__temp from that path. Verified empirically: reproducing the
crash leaves no temp table, and a real pre-upgrade database that lived
through the crash has none either. Drop the startup cleanup and the
test's manufactured temp table, which guarded a state that cannot arise.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VGNXRuSFe8PvDQYyX1BVDS
@jbouder
jbouder marked this pull request as ready for review August 28, 2026 16:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] - Startup crash on SQLite upgrade: dropping workspaces.package_manager fails with FOREIGN KEY constraint on populated databases

1 participant