hashicorp/nomad · error

Failed to load snapshot from archive: %w

Error message

Failed to load snapshot from archive: %w

What it means

RedactSnapshot wraps any failure from RestoreFromArchive, which parses the snapshot archive (tar.gz) and rebuilds the FSM and store. This means the input file could not be read as a valid Raft snapshot archive: bad format, corruption, unsupported structure, or unreadable content. The original error is preserved via %w for errors.As/Is inspection.

Source

Thrown at helper/raftutil/snapshot.go:59

	err = fsm.RestoreWithFilter(r, filter)
	if err != nil {
		return nil, nil, nil, fmt.Errorf("failed to restore from snapshot: %w", err)
	}

	select {
	case err := <-errCh:
		return nil, nil, nil, err
	case meta := <-metaCh:
		return fsm, fsm.State(), meta, nil
	}
}

func RedactSnapshot(srcFile *os.File) error {
	srcFile.Seek(0, 0)
	fsm, store, meta, err := RestoreFromArchive(srcFile, nil)
	if err != nil {
		return fmt.Errorf("Failed to load snapshot from archive: %w", err)
	}

	iter, err := store.RootKeys(nil)
	if err != nil {
		return fmt.Errorf("Failed to query for root keys: %v", err)
	}

	for {
		raw := iter.Next()
		if raw == nil {
			break
		}
		rootKey := raw.(*structs.RootKey)
		if rootKey == nil {
			break
		}
		if len(rootKey.WrappedKeys) > 0 {
			rootKey.KeyID = rootKey.KeyID + " [REDACTED]"

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Verify the file is a complete, valid snapshot archive (gzip/tar readable; e.g. `tar tzf snapshot.tar`) and re-download/re-take the snapshot if not.
  2. Check the wrapped error with errors.Unwrap to see the underlying cause (tar format, checksum, or FSM decode failure) and fix that specific issue.
  3. Confirm the snapshot came from the same or compatible product version as the tool doing the redaction.
  4. Ensure the file is seekable and readable: RestoreFromArchive seeks to 0 first; a closed or read-only fd will fail.

Example fix

// before
err := raftutil.RedactSnapshot(f) // f is a truncated/partial snapshot

// after
if fi, serr := f.Stat(); serr == nil && fi.Size() == 0 {
    return fmt.Errorf("snapshot file is empty; re-run consul snapshot save")
}
err := raftutil.RedactSnapshot(f)
Defensive patterns

Strategy: validation

Validate before calling

func validateSnapshotFile(f *os.File) error {
    fi, err := f.Stat()
    if err != nil {
        return err
    }
    if fi.Size() == 0 {
        return fmt.Errorf("snapshot file is empty")
    }
    // sniff gzip magic
    br := bufio.NewReader(f)
    magic, _ := br.Peek(2)
    f.Seek(0, 0)
    if len(magic) < 2 || magic[0] != 0x1f || magic[1] != 0x8b {
        return fmt.Errorf("not a gzip snapshot archive")
    }
    return nil
}

Try / catch

err := raftutil.RedactSnapshot(f)
var inner error
if err != nil && errors.Unwrap(err) != nil {
    inner = errors.Unwrap(err)
    log.Printf("snapshot load failed: %v (cause: %v)", err, inner)
}

Prevention

When it happens

Trigger: Calling helper/raftutil.RedactSnapshot with a *os.File whose contents are not a valid snapshot archive: empty file, truncated download, non-snapshot file, corrupt tar/gz stream, or an archive missing required snapshot members (meta.json, state.bin, logs.dat).

Common situations: Operator redacts a snapshot that was copied incompletely (scp/ctl-c mid-transfer), a snapshot produced by an incompatible Consul version, a file that is actually a BoltDB raft.db rather than a snapshot archive, or a 0-byte file created by the CLI before writing.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/72dd0da880793e8f. Report an issue: GitHub.