rqlite/rqlite · error

error swapping database file: %v

Error message

error swapping database file: %v

What it means

After a successful boot/restore, the Store swaps the freshly validated SQLite file into place via db.Swap(), which closes the current database handle and reopens the new file (reapplying FK constraints settings and WAL mode). If the swap fails (SQLite open error on the new file, missing WAL/journal handling problems, FK constraint flags mismatch, file I/O error), the restore fails with 'error swapping database file: %v'.

Source

Thrown at store/store.go:2025

		return n, err
	}

	// Confirm the data is a valid SQLite database.
	if !sql.IsValidSQLiteFile(f.Name()) {
		return n, fmt.Errorf("invalid SQLite data")
	}

	// Raft won't snapshot unless there is at least one unsnapshotted log entry,
	// so prep that now before we do anything destructive.
	if af, err := s.Noop("boot"); err != nil {
		return n, err
	} else if err := af.Error(); err != nil {
		return n, err
	}

	// Swap in new database file.
	if err := s.db.Swap(f.Name(), s.dbConf.FKConstraints, true); err != nil {
		return n, fmt.Errorf("error swapping database file: %v", err)
	}

	// Swapping in a new database unregisters any registered CDC hooks, so signal that it
	// needs to be reregistered on the next change.
	s.cdcRegistered.Unset()

	// Snapshot, so we load the new database into the Raft system.
	if err := s.snapshotStore.SetDueNext(snapshot.Full); err != nil {
		s.logger.Fatalf("failed to set full snapshot needed: %s", err)
	}
	if err := s.Snapshot(1); err != nil {
		return n, err
	}
	stats.Add(numBoots, 1)
	return n, nil
}

// Vacuum performs a VACUUM operation on the underlying database.

View on GitHub (pinned to 7586a4d1bd)

Solutions

  1. Check rqlited logs for the underlying SQLite open error and the data directory's permissions/free space.
  2. Retry the boot with the correct ?fk flag on /boot so FKConstraints matches the node configuration.
  3. Re-export/re-download the backup and verify it opens with the sqlite3 CLI locally.
  4. Stop write traffic, restart the node, and boot again to rule out transient races.

Example fix

# before
curl -X POST http://node:4001/boot --data-binary @backup.db
# after (FK-enabled node)
curl -X POST 'http://node:4001/boot?fk' --data-binary @backup.db
Defensive patterns

Strategy: retry

Validate before calling

cmd := exec.Command("sqlite3", "backup.db", "PRAGMA integrity_check;")
if err := cmd.Run(); err != nil {
    return errors.New("backup fails integrity check; do not boot from it")
}

Try / catch

resp, err := http.Post(bootURL, "application/octet-stream", body)
if resp.StatusCode != 200 && strings.Contains(readBody(resp), "error swapping database file") {
    checkDiskSpaceAndPerms(dataDir)
    retryBoot(withMatchingFkFlag)
}

Prevention

When it happens

Trigger: Calling /boot when the restored file cannot be opened/reopened by SQLite — e.g., file corrupted in a way IsValidSQLiteFile's header check passes but full open fails, filesystem permission problems on the data directory, or incompatible dbConf.FKConstraints state.

Common situations: Disk-full or permission errors on the data directory during swap; restoring a database created with different SQLite compile options or encryption; FKConstraints mismatch between the boot source and node configuration; concurrent operations racing the swap.

Related errors


AI-assisted analysis of rqlite/rqlite@7586a4d1bd (2026-09-03). Data as JSON: /api/errors/461adaca9d9f4053. Report an issue: GitHub.