{"record":{"id":"cf4c7899d6ec7767","repo":"VictoriaMetrics/VictoriaMetrics","slug":"unexpected-snapshot-name-q-it-must-match-q-rege","errorCode":null,"errorMessage":"unexpected snapshot name=%q; it must match %q regexp","messagePattern":"unexpected snapshot name=%q; it must match %q regexp","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/snapshot/snapshotutil/snapshotutil.go","lineNumber":24,"sourceCode":"\t\"strings\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger\"\n)\n\nvar snapshotNameRegexp = regexp.MustCompile(`^[0-9]{14}-[0-9A-Fa-f]+$`)\n\n// Validate validates the snapshotName\nfunc Validate(snapshotName string) error {\n\t_, err := Time(snapshotName)\n\treturn err\n}\n\n// Time returns snapshot creation time from the given snapshotName\nfunc Time(snapshotName string) (time.Time, error) {\n\tif !snapshotNameRegexp.MatchString(snapshotName) {\n\t\treturn time.Time{}, fmt.Errorf(\"unexpected snapshot name=%q; it must match %q regexp\", snapshotName, snapshotNameRegexp.String())\n\t}\n\tn := strings.IndexByte(snapshotName, '-')\n\tif n < 0 {\n\t\tlogger.Panicf(\"BUG: cannot find `-` in snapshotName=%q\", snapshotName)\n\t}\n\ts := snapshotName[:n]\n\tt, err := time.Parse(\"20060102150405\", s)\n\tif err != nil {\n\t\treturn time.Time{}, fmt.Errorf(\"unexpected timestamp=%q in snapshot name: %w; it must match YYYYMMDDhhmmss pattern\", s, err)\n\t}\n\treturn t, nil\n}\n\n// NewName returns new name for new snapshot\nfunc NewName() string {\n\treturn fmt.Sprintf(\"%s-%08X\", time.Now().UTC().Format(\"20060102150405\"), nextSnapshotIdx())\n}\n","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/VictoriaMetrics/VictoriaMetrics/blob/5079fb58f1e8e62113f90c945ad71586c797d770/lib/snapshot/snapshotutil/snapshotutil.go#L6-L42","documentation":"snapshotutil.Time() extracts the creation timestamp from a snapshot directory name, which must match ^[0-9]{14}-[0-9A-Fa-f]+$ (yyyyMMddHHmmss-hexID). If the given name doesn't match, the library returns this error naming the offending input and the required regexp. Callers like MustDeleteStaleSnapshots and Validate use it to decide whether a directory is a real snapshot.","triggerScenarios":"Passing a directory name that isn't a VM snapshot name to snapshotutil.Time() — e.g. retention/backup scripts iterating -snapshotAuthKey-less snapshot dirs that include manually created folders, tmp dirs like \"*tmp*\", or non-snapshot files.","commonSituations":"Cleanup scripts scanning the base snapshot path and encountering operator-created directories; leftover partially-created snapshot folders from crashed runs; custom tooling storing other data under the snapshots dir; older/newer VM versions with different naming.","solutions":["Only call Time() on directory names produced by the snapshot API; filter other entries before calling.","In cleanup code, ignore entries that fail the regexp instead of treating the error as fatal (use Validate/non-Must variants).","Remove or rename stray directories under the snapshots path that aren't valid snapshot names.","If a snapshot dir was manually renamed, restore the original 14-digit-timestamp-hexid name."],"exampleFix":"// before: panic on unknown entries\nfor _, fsEntry := range fsEntries {\n    snapshotutil.MustDeleteStaleSnapshots(fsEntry.Path(), maxAge) // panics on tmp dirs\n}\n// after: skip invalid names gracefully\nfor _, fsEntry := range fsEntries {\n    if err := snapshotutil.Validate(fsEntry.Path()); err != nil {\n        logger.Infof(\"skipping non-snapshot dir %q\", fsEntry.Path())\n        continue\n    }\n    snapshotutil.MustDeleteStaleSnapshots(fsEntry.Path(), maxAge)\n}","handlingStrategy":"validation","validationCode":"var snapshotNameRegexp = regexp.MustCompile(`^[0-9]{14}-[0-9A-Fa-f]+$`)\nfunc isSnapshotName(name string) bool { return snapshotNameRegexp.MatchString(name) }\n// guard:\nif !isSnapshotName(dirName) { continue } // skip non-snapshot entries before calling snapshotutil.Time","typeGuard":"func looksLikeSnapshotName(name string) bool {\n    return regexp.MustCompile(`^[0-9]{14}-[0-9A-Fa-f]+$`).MatchString(name)\n}","tryCatchPattern":"t, err := snapshotutil.Time(name)\nif err != nil {\n    logger.Infof(\"skipping %q: not a snapshot name (%v)\", name, err)\n    continue\n}","preventionTips":["Iterate only entries created via the snapshot API when doing retention cleanup.","Skip tmp or partially-created snapshot directories (names with 'tmp') instead of failing.","Never rename snapshot directories; keep the yyyyMMddHHmmss-hexid format.","Prefer Validate-based filtering over calling Time() on every directory entry."],"tags":["snapshot","validation","naming"],"backgroundTag":"invalid-snapshot-name","analyzedSha":"5079fb58f1e8e62113f90c945ad71586c797d770","analyzedAt":"2026-09-03T18:10:26.153Z","contentChangedAt":"2026-09-03T18:10:26.153Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}