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

  1. Check e.message: 'duplicate column name' is harmless — another process already added it; ignore.
  2. 'database is locked' — ensure only one instance runs against the DB, or enable WAL/retry.
  3. 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).
  4. 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

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


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/50d1ec2e3cba0876. Report an issue: GitHub.