{"record":{"id":"f26a2b5c5f4fe39c","repo":"benbjohnson/litestream","slug":"invalid-v0-3-x-wal-segment-filename-q","errorCode":null,"errorMessage":"invalid v0.3.x WAL segment filename: %q","messagePattern":"invalid v0\\.3\\.x WAL segment filename: %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3.go","lineNumber":134,"sourceCode":"// Returns an error if the filename does not match the expected format.\nfunc ParseSnapshotFilenameV3(filename string) (index int, err error) {\n\tm := snapshotRegexV3.FindStringSubmatch(filename)\n\tif m == nil {\n\t\treturn 0, fmt.Errorf(\"invalid v0.3.x snapshot filename: %q\", filename)\n\t}\n\tidx, err := strconv.ParseInt(m[1], 16, 32)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"invalid snapshot path: %s: %w\", filename, err)\n\t}\n\treturn int(idx), nil\n}\n\n// ParseWALSegmentFilenameV3 parses a v0.3.x WAL segment filename.\n// Returns the WAL index and byte offset, or an error if the filename is invalid.\nfunc ParseWALSegmentFilenameV3(filename string) (index int, offset int64, err error) {\n\tm := walSegmentRegexV3.FindStringSubmatch(filename)\n\tif m == nil {\n\t\treturn 0, 0, fmt.Errorf(\"invalid v0.3.x WAL segment filename: %q\", filename)\n\t}\n\tidx, err := strconv.ParseInt(m[1], 16, 32)\n\tif err != nil {\n\t\treturn 0, 0, fmt.Errorf(\"invalid wal segment path: %s: %w\", filename, err)\n\t}\n\toff, err := strconv.ParseInt(m[2], 16, 64)\n\tif err != nil {\n\t\treturn 0, 0, fmt.Errorf(\"invalid wal segment path: %s: %w\", filename, err)\n\t}\n\treturn int(idx), off, nil\n}\n\n// IsGenerationIDV3 returns true if s is a valid v0.3.x generation ID (16 hex chars).\nfunc IsGenerationIDV3(s string) bool {\n\treturn generationRegexV3.MatchString(s)\n}\n\n// ReplicaClientV3 reads v0.3.x backup data.","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/v3.go#L116-L152","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass only the base filename: apply filepath.Base() before parsing.","Verify the name matches '{index:08x}_{offset:08x}.wal.lz4'; skip files that don't when scanning directories.","For files written by Litestream v0.5+ (LTX format), use the LTX APIs, not the V3 parser.","Confirm the file is not a checkpoint or temporary file placed inside the wal/ directory."],"exampleFix":"// before\nidx, off, err := litestream.ParseWALSegmentFilenameV3(key) // key = \"gen/wal/00000000_00001000.wal.lz4\"\n\n// after\nidx, off, err := litestream.ParseWALSegmentFilenameV3(filepath.Base(key))","handlingStrategy":"validation","validationCode":"var walSegReV3 = regexp.MustCompile(`^[0-9a-f]{8}_[0-9a-f]{8}\\.wal\\.lz4$`)\nfunc isValidWALSegmentFilenameV3(name string) bool { return walSegReV3.MatchString(filepath.Base(name)) }","typeGuard":"func isV3WALSegmentName(s string) bool { return walSegReV3.MatchString(filepath.Base(s)) }\nif isV3WALSegmentName(key) { idx, off, err := litestream.ParseWALSegmentFilenameV3(filepath.Base(key)) }","tryCatchPattern":"idx, off, err := litestream.ParseWALSegmentFilenameV3(filepath.Base(name))\nif err != nil {\n    log.Printf(\"skipping %q: not a v0.3.x WAL segment: %v\", name, err)\n    continue\n}","preventionTips":["Pass the bare filename (filepath.Base), not the full replica key","Filter directory listings to *.wal.lz4 files before parsing","Use litestream.FormatWALSegmentFilenameV3 to generate names so they always round-trip","Keep v0.3.x and LTX-era files in separate code paths"],"tags":["filename-parsing","wal","v0-3-migration"],"backgroundTag":"invalid-argument-format","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}