{"record":{"id":"6561277e69c3bd52","repo":"containerd/containerd","slug":"snapshot-does-not-exist-w","errorCode":null,"errorMessage":"snapshot does not exist: %w","messagePattern":"snapshot does not exist: %w","errorType":"error_code","errorClass":"errdefs.ErrNotFound","httpStatus":null,"severity":"error","filePath":"core/snapshots/storage/bolt.go","lineNumber":105,"sourceCode":"\t\tgetUsage(bkt, &su)\n\t\treturn readSnapshot(bkt, &id, &si)\n\t})\n\tif err != nil {\n\t\treturn \"\", snapshots.Info{}, snapshots.Usage{}, err\n\t}\n\n\treturn strconv.FormatUint(id, 10), si, su, nil\n}\n\n// UpdateInfo updates an existing snapshot info's data\nfunc UpdateInfo(ctx context.Context, info snapshots.Info, fieldpaths ...string) (snapshots.Info, error) {\n\tupdated := snapshots.Info{\n\t\tName: info.Name,\n\t}\n\terr := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {\n\t\tsbkt := bkt.Bucket([]byte(info.Name))\n\t\tif sbkt == nil {\n\t\t\treturn fmt.Errorf(\"snapshot does not exist: %w\", errdefs.ErrNotFound)\n\t\t}\n\t\tif err := readSnapshot(sbkt, nil, &updated); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif len(fieldpaths) > 0 {\n\t\t\tfor _, path := range fieldpaths {\n\t\t\t\tif strings.HasPrefix(path, \"labels.\") {\n\t\t\t\t\tif updated.Labels == nil {\n\t\t\t\t\t\tupdated.Labels = map[string]string{}\n\t\t\t\t\t}\n\n\t\t\t\t\tkey := strings.TrimPrefix(path, \"labels.\")\n\t\t\t\t\tupdated.Labels[key] = info.Labels[key]\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tswitch path {","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/containerd/containerd/blob/4246446a2bf7d03837b0244118d858799393bd80/core/snapshots/storage/bolt.go#L87-L123","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n_, err := storage.Update(ctx, name, fieldpaths, info) // panics on missing snapshot\n// after\nif err := storage.GetInfo(ctx, name); err != nil && errdefs.IsNotFound(err) {\n    return nil // snapshot gone; skip update\n}\n_, err := storage.Update(ctx, name, fieldpaths, info)","handlingStrategy":"try-catch","validationCode":"if _, err := storage.GetInfo(ctx, name); err != nil {\n    return err // snapshot already absent; skip update\n}","typeGuard":"func snapshotGone(err error) bool { return errdefs.IsNotFound(err) }","tryCatchPattern":"_, err := storage.Update(ctx, name, fieldpaths, info)\nif errdefs.IsNotFound(err) {\n    return nil // concurrently removed; treat as no-op\n}\nreturn err","preventionTips":["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"],"tags":["snapshots","bolt","not-found","storage"],"backgroundTag":"snapshot-not-found","analyzedSha":"4246446a2bf7d03837b0244118d858799393bd80","analyzedAt":"2026-09-02T00:14:43.053Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}