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
- Quiesce all writers to the legacy database and retry the export
- Run the export once, not concurrently with other bd commands against the same repo
- Exclude the database path from sync/backup/antivirus scanning during export
- 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
- Quiesce all writers before export; treat this error as a signal of concurrent modification, not corruption
- Exclude the database path from sync clients, backups, and antivirus during export
- Don't run exports concurrently with other bd commands on the same repo
- Export from a frozen copy for unattended pipelines
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
- sealed legacy SQLite database does not match source fingerpr
- sealed legacy SQLite WAL does not match source fingerprint
- legacy SQLite source %q must not be a symlink
- legacy SQLite source %q must be a regular file
- --output must not alias legacy SQLite source or sidecar
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/3eb3153793d764c1.
Report an issue: GitHub.