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

  1. Ensure only one syncthing process uses the database directory (check for lock files and running instances)
  2. Restore the database from a backup, or move the old DB aside and let syncthing re-index the folder if history is expendable
  3. Fix permissions/ownership on the database directory and check ulimit -n
  4. 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

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


AI-assisted analysis of syncthing/syncthing@058bcd7334 (2026-08-15). Data as JSON: /api/errors/327127996d1380f3. Report an issue: GitHub.