VictoriaMetrics/VictoriaMetrics · error

unexpected snapshot name=%q; it must match %q regexp

Error message

unexpected snapshot name=%q; it must match %q regexp

What it means

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.

Source

Thrown at lib/snapshot/snapshotutil/snapshotutil.go:24

	"strings"
	"sync/atomic"
	"time"

	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
)

var snapshotNameRegexp = regexp.MustCompile(`^[0-9]{14}-[0-9A-Fa-f]+$`)

// Validate validates the snapshotName
func Validate(snapshotName string) error {
	_, err := Time(snapshotName)
	return err
}

// Time returns snapshot creation time from the given snapshotName
func Time(snapshotName string) (time.Time, error) {
	if !snapshotNameRegexp.MatchString(snapshotName) {
		return time.Time{}, fmt.Errorf("unexpected snapshot name=%q; it must match %q regexp", snapshotName, snapshotNameRegexp.String())
	}
	n := strings.IndexByte(snapshotName, '-')
	if n < 0 {
		logger.Panicf("BUG: cannot find `-` in snapshotName=%q", snapshotName)
	}
	s := snapshotName[:n]
	t, err := time.Parse("20060102150405", s)
	if err != nil {
		return time.Time{}, fmt.Errorf("unexpected timestamp=%q in snapshot name: %w; it must match YYYYMMDDhhmmss pattern", s, err)
	}
	return t, nil
}

// NewName returns new name for new snapshot
func NewName() string {
	return fmt.Sprintf("%s-%08X", time.Now().UTC().Format("20060102150405"), nextSnapshotIdx())
}

View on GitHub (pinned to 5079fb58f1)

Solutions

  1. Only call Time() on directory names produced by the snapshot API; filter other entries before calling.
  2. In cleanup code, ignore entries that fail the regexp instead of treating the error as fatal (use Validate/non-Must variants).
  3. Remove or rename stray directories under the snapshots path that aren't valid snapshot names.
  4. If a snapshot dir was manually renamed, restore the original 14-digit-timestamp-hexid name.

Example fix

// before: panic on unknown entries
for _, fsEntry := range fsEntries {
    snapshotutil.MustDeleteStaleSnapshots(fsEntry.Path(), maxAge) // panics on tmp dirs
}
// after: skip invalid names gracefully
for _, fsEntry := range fsEntries {
    if err := snapshotutil.Validate(fsEntry.Path()); err != nil {
        logger.Infof("skipping non-snapshot dir %q", fsEntry.Path())
        continue
    }
    snapshotutil.MustDeleteStaleSnapshots(fsEntry.Path(), maxAge)
}
Defensive patterns

Strategy: validation

Validate before calling

var snapshotNameRegexp = regexp.MustCompile(`^[0-9]{14}-[0-9A-Fa-f]+$`)
func isSnapshotName(name string) bool { return snapshotNameRegexp.MatchString(name) }
// guard:
if !isSnapshotName(dirName) { continue } // skip non-snapshot entries before calling snapshotutil.Time

Type guard

func looksLikeSnapshotName(name string) bool {
    return regexp.MustCompile(`^[0-9]{14}-[0-9A-Fa-f]+$`).MatchString(name)
}

Try / catch

t, err := snapshotutil.Time(name)
if err != nil {
    logger.Infof("skipping %q: not a snapshot name (%v)", name, err)
    continue
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of VictoriaMetrics/VictoriaMetrics@5079fb58f1 (2026-09-03). Data as JSON: /api/errors/cf4c7899d6ec7767. Report an issue: GitHub.