benbjohnson/litestream · error

invalid v0.3.x WAL segment filename: %q

Error message

invalid v0.3.x WAL segment filename: %q

What it means

ParseWALSegmentFilenameV3 extracts the WAL index and byte offset from a v0.3.x segment filename of the form '{index:08x}_{offset:08x}.wal.lz4' (e.g. '00000000_00001000.wal.lz4'). This error is returned when the filename does not match walSegmentRegexV3 at all. Litestream throws it when scanning v0.3.x replica WAL directories and encountering a name that is not a valid v0.3.x WAL segment.

Source

Thrown at v3.go:134

// 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)
	}
	off, err := strconv.ParseInt(m[2], 16, 64)
	if err != nil {
		return 0, 0, fmt.Errorf("invalid wal segment path: %s: %w", filename, err)
	}
	return int(idx), off, nil
}

// IsGenerationIDV3 returns true if s is a valid v0.3.x generation ID (16 hex chars).
func IsGenerationIDV3(s string) bool {
	return generationRegexV3.MatchString(s)
}

// ReplicaClientV3 reads v0.3.x backup data.

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Pass only the base filename: apply filepath.Base() before parsing.
  2. Verify the name matches '{index:08x}_{offset:08x}.wal.lz4'; skip files that don't when scanning directories.
  3. For files written by Litestream v0.5+ (LTX format), use the LTX APIs, not the V3 parser.
  4. Confirm the file is not a checkpoint or temporary file placed inside the wal/ directory.

Example fix

// before
idx, off, err := litestream.ParseWALSegmentFilenameV3(key) // key = "gen/wal/00000000_00001000.wal.lz4"

// after
idx, off, err := litestream.ParseWALSegmentFilenameV3(filepath.Base(key))
Defensive patterns

Strategy: validation

Validate before calling

var walSegReV3 = regexp.MustCompile(`^[0-9a-f]{8}_[0-9a-f]{8}\.wal\.lz4$`)
func isValidWALSegmentFilenameV3(name string) bool { return walSegReV3.MatchString(filepath.Base(name)) }

Type guard

func isV3WALSegmentName(s string) bool { return walSegReV3.MatchString(filepath.Base(s)) }
if isV3WALSegmentName(key) { idx, off, err := litestream.ParseWALSegmentFilenameV3(filepath.Base(key)) }

Try / catch

idx, off, err := litestream.ParseWALSegmentFilenameV3(filepath.Base(name))
if err != nil {
    log.Printf("skipping %q: not a v0.3.x WAL segment: %v", name, err)
    continue
}

Prevention

When it happens

Trigger: Calling ParseWALSegmentFilenameV3 with a non-conforming filename: an LTX-era '.wal' or '.ltx' name, a snapshot filename, a name with the wrong separator (e.g. '-' instead of '_'), a full path instead of the bare filename, or a truncated/corrupted name.

Common situations: Custom restore tooling iterating objects in a v0.3.x bucket's wal/ directory; mixing files from different Litestream versions in one directory; passing object keys with 'generations/<gen>/wal/' prefixes intact.

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


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/f26a2b5c5f4fe39c. Report an issue: GitHub.