gastownhall/beads · error
legacy SQLite source %q must be a regular file
Error message
legacy SQLite source %q must be a regular file
What it means
After rejecting symlinks, fingerprintFile also requires the path to be a regular file (info.Mode().IsRegular()). Directories, device nodes, sockets, FIFOs, and other special files cannot be safely copied and fingerprinted as a SQLite database, so Export refuses with this error before touching the data.
Source
Thrown at internal/migration/legacysqlite/reader.go:193
if err != nil {
return sourceSet{}, err
}
return sourceSet{db, wal, journal}, nil
}
func fingerprintFile(path string, required bool) (fingerprint, error) {
info, err := os.Lstat(path)
if os.IsNotExist(err) && !required {
return fingerprint{}, nil
}
if err != nil {
return fingerprint{}, err
}
if info.Mode()&os.ModeSymlink != 0 {
return fingerprint{}, fmt.Errorf("legacy SQLite source %q must not be a symlink", path)
}
if !info.Mode().IsRegular() {
return fingerprint{}, fmt.Errorf("legacy SQLite source %q must be a regular file", path)
}
f, err := os.Open(path) //nolint:gosec // G304: source is lstat-checked and fingerprinted again after sealing.
if err != nil {
return fingerprint{}, err
}
defer f.Close()
h := sha256.New()
if _, err = io.Copy(h, f); err != nil {
return fingerprint{}, err
}
return fingerprint{true, info.Size(), info.ModTime(), hex.EncodeToString(h.Sum(nil)), info}, nil
}
func sameSet(a, b sourceSet) bool {
return sameFingerprint(a.db, b.db) && sameFingerprint(a.wal, b.wal) && sameFingerprint(a.journal, b.journal)
}
func sameFingerprint(a, b fingerprint) bool {
return a.exists == b.exists && (!a.exists || (a.size == b.size && a.mod.Equal(b.mod) && a.digest == b.digest && os.SameFile(a.info, b.info)))View on GitHub (pinned to 71377f2769)
Solutions
- Check the path with ls -l or stat and pass the actual regular .db file, not a directory or special file
- If the database lives in a directory, use the path to beads.db inside it
- Remove/recreate the entry if it is a leftover FIFO/socket: delete it and restore a real SQLite file from backup
Example fix
// before $ bd migrate --legacy ./legacy-data # a directory // error: legacy SQLite source "./legacy-data" must be a regular file // after $ bd migrate --legacy ./legacy-data/beads.db ...
Defensive patterns
Strategy: validation
Validate before calling
func requireRegularFile(path string) error {
info, err := os.Stat(path)
if err != nil { return err }
if !info.Mode().IsRegular() {
return fmt.Errorf("%s is not a regular file (dir=%v, other)", path, info.IsDir())
}
return nil
}
// call before Export: requireRegularFile(src) Type guard
func isPlainFile(path string) bool {
info, err := os.Stat(path)
return err == nil && info.Mode().IsRegular()
} Try / catch
if !isPlainFile(src) {
return fmt.Errorf("--legacy must point at the .db file itself, got %q", src)
}
if err := legacysqlite.Export(ctx, src, out, os.Stdout); err != nil { return err } Prevention
- Pass the .db file path, never a directory or special file
- Verify with stat before wiring the path into automated migration jobs
- Clean up leftover FIFOs/sockets that may occupy the beads.db name
- Fix scripts that create the path so they write a regular file
When it happens
Trigger: Export -> seal -> fingerprintSource -> fingerprintFile where Lstat succeeds but the mode is not a regular file and not a symlink — e.g. the source path is a directory, a named pipe, a device node, or (for required paths like the .db) any non-regular entry.
Common situations: Typo where the user passes a directory (or the repo root) as the legacy source; passing a device or socket by mistake; a broken setup where beads.db is a FIFO created by a script.
Related errors
- issue %s has invalid %s boolean
- --source-db and --output are required
- ExternalDoltConfig: Socket %q is not absolute
- ExternalDoltConfig: TLSCert %q is not absolute
- ExternalDoltConfig: TLSKey %q is not absolute
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/57a482e03d777601.
Report an issue: GitHub.