syncthing/syncthing · critical
loading small index:
Error message
loading small index:
What it means
The legacy-database small index (a string↔uint32 ID map persisted in the DB under a prefix) panics when NewPrefixIterator cannot be created for its key prefix. This runs at construction time (newSmallIndex → load), so a DB-level failure here is treated as unrecoverable corruption/misconfiguration of the underlying key-value store rather than a handled error.
Source
Thrown at internal/db/olddb/smallindex.go:45
}
func newSmallIndex(db backend.Backend, prefix []byte) *smallIndex {
idx := &smallIndex{
db: db,
prefix: prefix,
id2val: make(map[uint32]string),
val2id: make(map[string]uint32),
}
idx.load()
return idx
}
// load iterates over the prefix space in the database and populates the in
// memory maps.
func (i *smallIndex) load() {
it, err := i.db.NewPrefixIterator(i.prefix)
if err != nil {
panic("loading small index: " + err.Error())
}
defer it.Release()
for it.Next() {
val := string(it.Value())
id := binary.BigEndian.Uint32(it.Key()[len(i.prefix):])
if val != "" {
// Empty value means the entry has been deleted.
i.id2val[id] = val
i.val2id[val] = id
}
if id >= i.nextID {
i.nextID = id + 1
}
}
}
// ID returns the index number for the given byte slice, allocating a new one
// and persisting this to the database if necessary.View on GitHub (pinned to 058bcd7334)
Solutions
- Ensure only one syncthing process uses the database directory (check for lock files and running instances)
- Restore the database from a backup, or move the old DB aside and let syncthing re-index the folder if history is expendable
- Fix permissions/ownership on the database directory and check ulimit -n
- If it occurs during an upgrade, roll back to the previous syncthing version, complete a clean shutdown, then upgrade again
Defensive patterns
Strategy: fallback
Validate before calling
// pre-flight: refuse to start if the db dir is locked or unwritable
if _, err := os.OpenFile(filepath.Join(dbDir, "lock"), os.O_CREATE|os.O_EXCL, 0o600); err == nil {
os.Remove(filepath.Join(dbDir, "lock"))
} else if os.IsExist(err) {
return errors.New("database appears in use by another process")
} Prevention
- Enforce single-instance operation per data directory (systemd, container orchestration)
- Back up the index database before upgrades
- Never mix database files produced by different syncthing major versions
When it happens
Trigger: Opening an old/corrupt database where the prefix iterator cannot be created — open file descriptor exhaustion, DB reopened concurrently by another process holding a lock, corrupted/mismatched backend files during a legacy (LevelDB→PEBBLE/sqlite) migration, or a read-only database file.
Common situations: Two syncthing instances pointed at the same data dir; crash mid-migration leaving a mixed old/new DB; permissions changed on index.db; FD limits hit after many folder restarts.
Related errors
- delete invalid pending device: %w
- delete invalid pending folder: %w
- error getting sequence number: %w
- Error starting the main Syncthing process
- Failed to expand locations at init time
AI-assisted analysis of syncthing/syncthing@058bcd7334 (2026-08-15).
Data as JSON: /api/errors/327127996d1380f3.
Report an issue: GitHub.