decolua/9router · warning
[DB][sync] add column ${tableName}.${colName} failed: ${e.me
Error message
[DB][sync] add column ${tableName}.${colName} failed: ${e.message} What it means
Non-fatal warning from syncSchemaFromTables(), which keeps the SQLite schema in sync with table definitions by ALTER TABLE ... ADD COLUMN for missing columns. The column definition is sanitized (NOT NULL/UNIQUE/PRIMARY KEY/UNIQUE stripped); if the ALTER still fails, it logs this warning and continues — the schema drift persists but startup is not blocked.
Source
Thrown at src/lib/db/migrate.js:99
// Create table if absent
adapter.exec(buildCreateTableSql(tableName, def));
// Diff columns
const existing = adapter.all(`PRAGMA table_info(${tableName})`);
const existingNames = new Set(existing.map((r) => r.name));
for (const [colName, colDef] of Object.entries(def.columns)) {
if (!existingNames.has(colName)) {
// SQLite ADD COLUMN restrictions: no PRIMARY KEY / UNIQUE w/o NULL ok.
// We strip PRIMARY KEY / UNIQUE since those are only valid at create time.
const safeDef = colDef
.replace(/PRIMARY KEY( AUTOINCREMENT)?/i, "")
.replace(/UNIQUE/i, "")
.trim();
try {
adapter.exec(`ALTER TABLE ${tableName} ADD COLUMN ${colName} ${safeDef}`);
console.log(`[DB][sync] +column ${tableName}.${colName}`);
} catch (e) {
console.warn(`[DB][sync] add column ${tableName}.${colName} failed: ${e.message}`);
}
}
}
// Indexes (idempotent)
for (const idx of def.indexes || []) {
try { adapter.exec(idx); } catch {}
}
}
}
// ─── Legacy JSON import (one-time) ───────────────────────────────────────
function importLegacyMain(adapter, data) {
if (!data || typeof data !== "object") return;
if (data.settings) {
adapter.run(`INSERT INTO settings(id, data) VALUES(1, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data`, [stringifyJson(data.settings)]);
}View on GitHub (pinned to 90b52e06ff)
Solutions
- Check e.message: 'duplicate column name' is harmless — another process already added it; ignore.
- 'database is locked' — ensure only one instance runs against the DB, or enable WAL/retry.
- Fix the table definition in src/lib/db/migrations/ so the column's DEFAULT/CONSTRAINT is valid for ALTER TABLE ADD COLUMN (SQLite only allows constant DEFAULTs and cannot add PRIMARY KEY columns).
- Back up the DB file, then stop the app, remove the stale marker/lock, and restart so sync re-runs cleanly.
Example fix
// before (migration table def)
columns: { quota: "INTEGER NOT NULL UNIQUE DEFAULT 0" }
// after (SQLite ADD COLUMN cannot apply UNIQUE / non-constant NOT NULL DEFAULTs)
columns: { quota: "INTEGER DEFAULT 0" } Defensive patterns
Strategy: try-catch
Validate before calling
// Detect missing columns before startup so sync succeeds on first run
import Database from "better-sqlite3";
const db = new Database(DATA_FILE);
const cols = db.pragma(`table_info(${tableName})`).map(c => c.name);
if (!cols.includes("expectedColumn")) console.warn("Schema drift — sync will ALTER TABLE on next start"); Try / catch
try { await getAdapter(); }
catch (e) { /* sync failures are warnings, not throws — check logs for '[DB][sync] add column' */ }
if (getLogs().some(l => l.includes("[DB][sync] add column")) ) console.warn("Schema drift persisted — inspect migration definitions"); Prevention
- Run only one app instance per DB file to avoid concurrent ALTER TABLE lock/duplicate-column races.
- Keep migration column definitions SQLite-ALTER-safe: no UNIQUE, no PRIMARY KEY, only constant DEFAULTs.
- Enable WAL mode to reduce 'database is locked' errors during startup sync.
- After schema changes, restart once cleanly and verify the [DB][sync] +column lines appear without warnings.
When it happens
Trigger: ALTER TABLE ... ADD COLUMN fails because: the column already exists (race between multiple instances migrating simultaneously, or a stale marker), a lock on the database (another connection holds a write transaction), the sanitized definition is still invalid SQL for SQLite (e.g. unsupported constraint surviving the sanitization), or a disk I/O error.
Common situations: Two app instances starting at once against the same DB file; DB file opened read-only; custom table definitions in migrations/ adding columns with constraints SQLite can't add via ALTER; interrupted previous migration leaving inconsistent state.
Related errors
- [DB] No SQLite driver available (bun/better/node/sql.js all
- [DB] bun:sqlite unavailable: ${e.message}
- [DB] node:sqlite unavailable: ${e.message}
- [DB][migrate] pre-schema backup failed (continuing): ${e.mes
- Failed to export database
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/50d1ec2e3cba0876.
Report an issue: GitHub.