containerd/containerd · error · errdefs.ErrNotFound
snapshot does not exist: %w
Error message
snapshot does not exist: %w
What it means
UpdateSnapshot (bolt-backed snapshot storage) looks up the snapshot's bucket by name before applying an update. If no bucket exists for that name, the snapshot does not exist in the metadata store and errdefs.ErrNotFound is wrapped. The update transaction aborts without modification.
Source
Thrown at core/snapshots/storage/bolt.go:105
getUsage(bkt, &su)
return readSnapshot(bkt, &id, &si)
})
if err != nil {
return "", snapshots.Info{}, snapshots.Usage{}, err
}
return strconv.FormatUint(id, 10), si, su, nil
}
// UpdateInfo updates an existing snapshot info's data
func UpdateInfo(ctx context.Context, info snapshots.Info, fieldpaths ...string) (snapshots.Info, error) {
updated := snapshots.Info{
Name: info.Name,
}
err := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {
sbkt := bkt.Bucket([]byte(info.Name))
if sbkt == nil {
return fmt.Errorf("snapshot does not exist: %w", errdefs.ErrNotFound)
}
if err := readSnapshot(sbkt, nil, &updated); err != nil {
return err
}
if len(fieldpaths) > 0 {
for _, path := range fieldpaths {
if strings.HasPrefix(path, "labels.") {
if updated.Labels == nil {
updated.Labels = map[string]string{}
}
key := strings.TrimPrefix(path, "labels.")
updated.Labels[key] = info.Labels[key]
continue
}
switch path {View on GitHub (pinned to 4246446a2b)
Solutions
- Verify the snapshot exists (e.g. via Statistics/Usage/GetInfo) before calling Update.
- Check the name/fieldpaths arguments for typos.
- Handle errdefs.IsNotFound(err) gracefully in the caller — the snapshot may have been concurrently deleted.
- Ensure the correct context (with the same storage transaction/DB) is used.
Example fix
// before
_, err := storage.Update(ctx, name, fieldpaths, info) // panics on missing snapshot
// after
if err := storage.GetInfo(ctx, name); err != nil && errdefs.IsNotFound(err) {
return nil // snapshot gone; skip update
}
_, err := storage.Update(ctx, name, fieldpaths, info) Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := storage.GetInfo(ctx, name); err != nil {
return err // snapshot already absent; skip update
} Type guard
func snapshotGone(err error) bool { return errdefs.IsNotFound(err) } Try / catch
_, err := storage.Update(ctx, name, fieldpaths, info)
if errdefs.IsNotFound(err) {
return nil // concurrently removed; treat as no-op
}
return err Prevention
- Check existence before updating snapshot metadata
- Treat ErrNotFound on update as a benign race in concurrent code
- Use consistent transactions when reading then updating snapshots
When it happens
Trigger: Calling snapshots storage Update (UpdateSnapshot) with an info.Name that has no existing snapshot bucket — updating a snapshot that was already removed, never created, or whose name is wrong.
Common situations: Double-removal race where a snapshot is deleted between lookup and update; referencing a snapshot in a different bolt DB/context transaction; stale cache of snapshot names.
Related errors
- failed to get active snapshot %q: %w
- missing parent %q of snapshot %q: %w
- NotFound
- parent does not exist: %w
- missing parent %q bucket: %w
AI-assisted analysis of containerd/containerd@4246446a2b (2026-09-02).
Data as JSON: /api/errors/6561277e69c3bd52.
Report an issue: GitHub.