kopia/kopia · error

unable to get snapshot root for

Error message

unable to get snapshot root for %v

What it means

CalculateStorageStats wraps a failure from SnapshotRoot(rep, snap) with "unable to get snapshot root for %v" where %v is "source@startTime". SnapshotRoot loads the root directory entry of a snapshot manifest from the repository object store; if the root object ID cannot be resolved or read, stats computation stops for the whole manifest list.

Solutions

  1. Inspect the wrapped error: if it is object-not-found for the root object, the snapshot is broken — remove it from the manifests slice and continue with the rest.
  2. Run repository consistency tools (kopia repository verify / maintenance) to repair or prune damaged snapshots.
  3. Confirm the manifests were produced from the same repo (rep) you pass in; mixing repos yields unresolvable root entries.
  4. Guard the call: fetch SnapshotRoot yourself first and skip manifests whose root cannot be loaded instead of failing the entire batch.

Example fix

// before
err := CalculateStorageStats(ctx, rep, allManifests, cb) // fails on one bad snapshot
// after
var valid []*snapshot.Manifest
for _, m := range allManifests {
    if _, err := SnapshotRoot(rep, m); err == nil {
        valid = append(valid, m)
    }
}
err := CalculateStorageStats(ctx, rep, valid, cb)
Defensive patterns

Strategy: validation

Validate before calling

for _, m := range manifests {
    if _, err := SnapshotRoot(rep, m); err != nil {
        return fmt.Errorf("snapshot %v has unreadable root: %w", m.ID, err)
    }
}

Type guard

func hasRoot(rep repo.Repository, m *snapshot.Manifest) bool {
    _, err := SnapshotRoot(rep, m)
    return err == nil
}

Try / catch

err := CalculateStorageStats(ctx, rep, manifests, cb)
if err != nil && strings.Contains(err.Error(), "unable to get snapshot root") {
    // skip/filter broken manifests and retry
}

Prevention

When it happens

Trigger: Calling CalculateStorageStats with a manifest whose root object ID points to a missing/corrupted object, or whose RootEntry cannot be loaded (e.g. deleted or pruned underlying objects), causing SnapshotRoot to return an error.

Common situations: Repository corruption or blobs deleted by aggressive maintenance; a manifest from a different repository/store than the one passed in; partial restore/migration where the snapshot metadata exists but the referenced root object is gone.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07). Data as JSON: /api/errors/8cbe2c34fec41da3. Report an issue: GitHub.

Appendix: source

Thrown at snapshot/snapshotfs/snapshot_storage_stats.go:97

			return nil
		},
	})
	if twerr != nil {
		return errors.Wrap(twerr, "tree walker")
	}
	defer tw.Close(ctx)

	src := manifests[0].Source

	for _, snap := range manifests {
		*unique = snapshot.StorageUsageDetails{}

		rootName := src.String() + "@" + snap.StartTime.Format(time.RFC3339)

		root, err := SnapshotRoot(rep, snap)
		if err != nil {
			return errors.Wrapf(err, "unable to get snapshot root for %v", rootName)
		}

		if err := tw.Process(ctx, root, rootName); err != nil {
			return errors.Wrapf(err, "error processing %v", rootName)
		}

		snap.StorageStats = &snapshot.StorageStats{
			NewData:      *unique,
			RunningTotal: *runningTotal,
		}

		if err := callback(snap); err != nil {
			return err
		}
	}

	return nil
}

View on GitHub (pinned to 82495e54b5)