benbjohnson/litestream · error
invalid v0.3.x snapshot filename: %q
Error message
invalid v0.3.x snapshot filename: %q
What it means
ParseSnapshotFilenameV3 extracts the integer index from a v0.3.x snapshot filename, which must match the format '{index:08x}.snapshot.lz4' (e.g. '00000000.snapshot.lz4'). This error is returned when the filename does not match the snapshotRegexV3 pattern at all, meaning the file is not recognized as a v0.3.x snapshot. Litestream throws it to defend against parsing garbage or foreign files found while scanning a v0.3.x replica layout.
Source
Thrown at v3.go:120
// FormatWALSegmentFilenameV3 returns the filename for a v0.3.x WAL segment.
// Format: {index:08x}_{offset:08x}.wal.lz4
func FormatWALSegmentFilenameV3(index int, offset int64) string {
return fmt.Sprintf("%08x_%08x.wal.lz4", index, offset)
}
var (
snapshotRegexV3 = regexp.MustCompile(`^([0-9a-f]{8})\.snapshot\.lz4$`)
walSegmentRegexV3 = regexp.MustCompile(`^([0-9a-f]{8})_([0-9a-f]{8,16})\.wal\.lz4$`)
generationRegexV3 = regexp.MustCompile(`^[0-9a-f]{16}$`)
)
// ParseSnapshotFilenameV3 parses a v0.3.x snapshot filename and returns the index.
// Returns an error if the filename does not match the expected format.
func ParseSnapshotFilenameV3(filename string) (index int, err error) {
m := snapshotRegexV3.FindStringSubmatch(filename)
if m == nil {
return 0, fmt.Errorf("invalid v0.3.x snapshot filename: %q", filename)
}
idx, err := strconv.ParseInt(m[1], 16, 32)
if err != nil {
return 0, fmt.Errorf("invalid snapshot path: %s: %w", filename, err)
}
return int(idx), nil
}
// ParseWALSegmentFilenameV3 parses a v0.3.x WAL segment filename.
// Returns the WAL index and byte offset, or an error if the filename is invalid.
func ParseWALSegmentFilenameV3(filename string) (index int, offset int64, err error) {
m := walSegmentRegexV3.FindStringSubmatch(filename)
if m == nil {
return 0, 0, fmt.Errorf("invalid v0.3.x WAL segment filename: %q", filename)
}
idx, err := strconv.ParseInt(m[1], 16, 32)
if err != nil {
return 0, 0, fmt.Errorf("invalid wal segment path: %s: %w", filename, err)View on GitHub (pinned to 4ed7a308f6)
Solutions
- Pass only the base filename, not the full path: use filepath.Base(path) before calling ParseSnapshotFilenameV3.
- Verify the filename matches the v0.3.x format '{index:08x}.snapshot.lz4'; use IsGenerationIDV3/regex or skip non-matching files when scanning a directory.
- If the file is an LTX file from a newer Litestream, do not use the V3 parser; use the current LTX parsing APIs instead.
- Check that the file is a genuine v0.3.x snapshot and not a manifest or unrelated file that landed in the snapshots/ directory.
Example fix
// before idx, err := litestream.ParseSnapshotFilenameV3(objKey) // objKey = "generations/abcdef0123456789/snapshots/00000000.snapshot.lz4" // after idx, err := litestream.ParseSnapshotFilenameV3(filepath.Base(objKey))
Defensive patterns
Strategy: validation
Validate before calling
var snapshotReV3 = regexp.MustCompile(`^[0-9a-f]{8}\.snapshot\.lz4$`)
func isValidSnapshotFilenameV3(name string) bool { return snapshotReV3.MatchString(filepath.Base(name)) } Type guard
func isV3SnapshotName(s string) bool { return snapshotReV3.MatchString(filepath.Base(s)) }
if isV3SnapshotName(key) { idx, err := litestream.ParseSnapshotFilenameV3(filepath.Base(key)) } Try / catch
idx, err := litestream.ParseSnapshotFilenameV3(filepath.Base(name))
if err != nil {
log.Printf("skipping non-v0.3.x snapshot %q: %v", name, err)
return skipFile
} Prevention
- Always pass filepath.Base(name), never a full object key or path
- Pre-validate names with a regex identical to ^[0-9a-f]{8}\.snapshot\.lz4$ before parsing
- When listing replica objects, filter to the snapshots/ directory and skip known non-snapshot files
- Never mix LTX-era filenames into V3 parsing code paths
When it happens
Trigger: Calling ParseSnapshotFilenameV3 with a filename that doesn't match the v0.3.x format: a v0.3.x-era name variant, an LTX-era name like '0000000000000000-0000000000000001.ltx', a path with directories included instead of the bare filename, an uncompressed '.snapshot' (missing .lz4), or a typo'd/corrupted name.
Common situations: Migrating from Litestream v0.3.x to newer versions and scanning old replica buckets manually; custom tooling that lists replica objects and parses names; passing a full object key/path instead of the base filename; extra files (checkpoints, manifests) dropped into the snapshots directory.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- invalid v0.3.x WAL segment filename: %q
- snapshot interval must be greater than 0
- snapshot retention must be greater than 0
- compaction interval must be greater than 0
- sync interval must be greater than 0
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/ef744fe26d75dd14.
Report an issue: GitHub.