rqlite/rqlite · error

failed to open old state file %s: %s

Error message

failed to open old state file %s: %s

What it means

Upgrade7To8 found the newest v7 snapshot metadata but could not open its state file '<old>/<id>/state.bin' with os.Open. This means the v7 snapshot data referenced by the metadata is missing or unreadable — the meta.json survived but the state.bin did not. The upgrade aborts and the temp directory is cleaned up.

Source

Thrown at snapshot/upgrader.go:118

	if err := writeMeta(newSnapshotPath, oldMeta); err != nil {
		return fmt.Errorf("failed to write new snapshot meta file to %s: %s", newSnapshotPath, err)
	}

	// Ensure all file handles are closed before any directory is renamed or removed.
	if err := func() error {
		// Write SQLite database file into new snapshot dir.
		newSqlitePath := filepath.Join(newTmpDir, oldMeta.ID+".db")
		newSqliteFd, err := os.Create(newSqlitePath)
		if err != nil {
			return fmt.Errorf("failed to create new SQLite file %s: %s", newSqlitePath, err)
		}
		defer newSqliteFd.Close()

		// Copy the old state file into the new generation directory.
		oldStatePath := filepath.Join(old, oldMeta.ID, v7StateFile)
		stateFd, err := os.Open(oldStatePath)
		if err != nil {
			return fmt.Errorf("failed to open old state file %s: %s", oldStatePath, err)
		}
		defer stateFd.Close()
		sz, err := fsutil.FileSize(oldStatePath)
		if err != nil {
			return fmt.Errorf("failed to get size of old state file %s: %s", oldStatePath, err)
		}
		logger.Printf("successfully opened old state file at %s (%d bytes in size)", oldStatePath, sz)

		headerLength := int64(16)
		if sz < headerLength {
			return fmt.Errorf("old state file %s is too small to be valid", oldStatePath)
		} else if sz == headerLength {
			logger.Printf("old state file %s contains no database data, no data to upgrade", oldStatePath)
		} else {
			// Skip past the header and length of the old state file.
			if _, err := stateFd.Seek(headerLength, 0); err != nil {
				return fmt.Errorf("failed to seek to beginning of old SQLite data %s: %s", oldStatePath, err)
			}

View on GitHub (pinned to 7586a4d1bd)

Solutions

  1. Inspect '<old>/<id>/' — if state.bin is missing or truncated, delete that incomplete snapshot directory and retry, or restore from backup.
  2. Restore the node's data directory (or use /boot) from a good backup, since the referenced snapshot data is unrecoverable.
  3. Fix read permissions on the snapshot subdirectory and state.bin for the rqlited process user.
  4. If other valid v7 snapshots exist, ensure the newest one is the complete one; consider removing only the broken snapshot directory so upgrade picks a complete snapshot.

Example fix

// before
//  rsnapshots/v7/<id>/meta.json exists, state.bin missing
// after
rm -rf /path/node/data/rsnapshots/v7/<id-without-state.bin>
# restart rqlited; upgrade proceeds with remaining complete snapshots or clean path
Defensive patterns

Strategy: validation

Validate before calling

// Go: verify the newest v7 snapshot's state file exists before upgrading
func newestV7StateFilePresent(old string) (bool, error) {
	entries, err := os.ReadDir(old)
	if err != nil { return false, err }
	for _, e := range entries {
		if e.IsDir() && fsutil.FileExists(filepath.Join(old, e.Name(), "meta.json")) {
			return fsutil.FileExists(filepath.Join(old, e.Name(), "state.bin")), nil
		}
	}
	return false, nil
}

Prevention

When it happens

Trigger: os.Open(filepath.Join(old, oldMeta.ID, "state.bin")) fails: the state.bin file was deleted, the snapshot subdirectory is incomplete, or permissions deny read access.

Common situations: Crash or disk-full during a previous v7 snapshot write left a snapshot directory with meta.json but no/partial state.bin; manual cleanup scripts deleted state.bin files; backups restored without data files; permissions changed after a user migration.

Related errors


AI-assisted analysis of rqlite/rqlite@7586a4d1bd (2026-09-03). Data as JSON: /api/errors/23a36d9311da632b. Report an issue: GitHub.