Problem
The ensure_workspace_schema_and_backfill function in backend/src/db.rs uses let _ = conn.execute(...) to ignore errors from schema migration statements:
fn ensure_workspace_schema_and_backfill(conn: &duckdb::Connection) {
let _ = conn.execute("ALTER TABLE users ADD COLUMN current_workspace_id VARCHAR", []);
let _ = conn.execute("ALTER TABLE files ADD COLUMN workspace_id VARCHAR", []);
let _ = conn.execute("ALTER TABLE workspaces ADD COLUMN slug VARCHAR", []);
// ... more ALTER TABLE statements ...
let _ = conn.execute("DROP INDEX IF EXISTS idx_fonts_workspace_fontstack", []);
recover_detached_workspace_members(conn).expect("Failed to recover detached workspace members");
backfill_workspace_data(conn).expect("Failed to backfill workspace data");
}
Impact
In DuckDB 1.5.4+, a failed DDL statement (e.g., adding a column that already exists) can cause the transaction to abort. When this happens, ALL subsequent statements fail with:
TransactionContext Error: Current transaction is aborted (please ROLLBACK)
This is the root cause of the PR #344 CI failures — all 158 backend tests fail because the database cannot initialize. The same pattern affects the PostGIS integration tests (6 failures) and E2E tests (50 failures).
The recover_detached_workspace_members call panics with .expect(), crashing the server on startup.
Reproduction
- Initialize a DuckDB database with DuckDB 1.5.4 (spatial extension 1.5.4)
- Call
init_database() on a database that already has some of the schema columns
- The ALTER TABLE statements fail silently, aborting the transaction
recover_detached_workspace_members panics
Fix Suggestion
- Replace
let _ = conn.execute(...) with error-aware logic that checks if the error is "column already exists" (expected) vs. a real failure
- If the transaction is aborted, call
ROLLBACK before continuing
- Consider wrapping each migration step in its own transaction
- Replace
.expect() with proper error handling that logs the failure and exits gracefully
fn run_migration_step(conn: &duckdb::Connection, sql: &str) {
if let Err(e) = conn.execute(sql, []) {
let msg = e.to_string();
// These errors are expected when the column/index already exists
if !msg.contains("already exists") && !msg.contains("duplicate") {
tracing::warn!(sql = %sql, error = %msg, "Unexpected migration error");
// Try to recover transaction state
let _ = conn.execute("ROLLBACK", []);
}
}
}
Severity
Critical — Blocks all CI, prevents server startup after DuckDB 1.5.4 upgrade.
Context
Problem
The
ensure_workspace_schema_and_backfillfunction inbackend/src/db.rsuseslet _ = conn.execute(...)to ignore errors from schema migration statements:Impact
In DuckDB 1.5.4+, a failed DDL statement (e.g., adding a column that already exists) can cause the transaction to abort. When this happens, ALL subsequent statements fail with:
This is the root cause of the PR #344 CI failures — all 158 backend tests fail because the database cannot initialize. The same pattern affects the PostGIS integration tests (6 failures) and E2E tests (50 failures).
The
recover_detached_workspace_memberscall panics with.expect(), crashing the server on startup.Reproduction
init_database()on a database that already has some of the schema columnsrecover_detached_workspace_memberspanicsFix Suggestion
let _ = conn.execute(...)with error-aware logic that checks if the error is "column already exists" (expected) vs. a real failureROLLBACKbefore continuing.expect()with proper error handling that logs the failure and exits gracefullySeverity
Critical — Blocks all CI, prevents server startup after DuckDB 1.5.4 upgrade.
Context