gastownhall/beads · error

legacy SQLite source changed while sealing

Error message

legacy SQLite source changed while sealing

What it means

After copying the db and WAL into the sealed temp directory, seal re-fingerprints the entire source set (db, wal, journal) and compares it with the pre-copy fingerprints, including size, mtime, digest, and inode identity (os.SameFile). This error means the source changed — in existence, content, or identity — between the before and after fingerprints, so the sealed snapshot may mix old and new states. Export aborts to guarantee exports are point-in-time consistent.

Source

Thrown at internal/migration/legacysqlite/reader.go:157

		if err == nil {
			err = fmt.Errorf("sealed legacy SQLite database does not match source fingerprint")
		}
		return fail(err)
	}
	if before.wal.exists {
		if copied, err := fingerprintFile(filepath.Join(dir, "legacy.db-wal"), true); err != nil || copied.digest != before.wal.digest {
			if err == nil {
				err = fmt.Errorf("sealed legacy SQLite WAL does not match source fingerprint")
			}
			return fail(err)
		}
	}
	after, err := fingerprintSource(resolved)
	if err != nil {
		return fail(err)
	}
	if !sameSet(before, after) {
		return fail(fmt.Errorf("legacy SQLite source changed while sealing"))
	}
	return sealedDB{dir: dir, db: filepath.Join(dir, "legacy.db"), source: resolved}, nil
}

func fingerprintSource(path string) (sourceSet, error) {
	db, err := fingerprintFile(path, true)
	if err != nil {
		return sourceSet{}, err
	}
	wal, err := fingerprintFile(path+"-wal", false)
	if err != nil {
		return sourceSet{}, err
	}
	if _, err := fingerprintFile(path+"-shm", false); err != nil {
		return sourceSet{}, err
	}
	journal, err := fingerprintFile(path+"-journal", false)
	if err != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Quiesce all writers to the legacy database and retry the export
  2. Run the export once, not concurrently with other bd commands against the same repo
  3. Exclude the database path from sync/backup/antivirus scanning during export
  4. Export from a frozen copy: cp beads.db beads.db-wal (while stopped) to a local dir and export that

Example fix

// before
$ bd migrate --legacy ./live/beads.db ...   # while bd sync runs
// error: legacy SQLite source changed while sealing
// after
$ bd sync stop && bd migrate --legacy ./live/beads.db ...
Defensive patterns

Strategy: retry

Try / catch

// single safe retry: quiesce, then re-run Export
if err := legacysqlite.Export(ctx, src, out, os.Stdout); err != nil {
	if strings.Contains(err.Error(), "changed while sealing") && !retried {
		stopWriters(src) // stop daemons/sync; then retry exactly once
		retried = true
		return legacysqlite.Export(ctx, src, out, os.Stdout)
	}
	return err
}

Prevention

When it happens

Trigger: Export -> seal: sameSet(before, after) is false because fingerprintSource(resolved) after the copy disagrees with the before snapshot on db, -wal, or -journal (any of: missing, size, mtime, digest, or same inode).

Common situations: A writer commits a transaction during the export; WAL auto-checkpoint rewrites the WAL; a sync client replaces the file (new inode); backup/AV tools touch mtime; a journal file appears mid-run.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/3eb3153793d764c1. Report an issue: GitHub.