{"record":{"id":"1b6bfa14f80c14e6","repo":"benbjohnson/litestream","slug":"invalid-snapshot-path-s-w","errorCode":null,"errorMessage":"invalid snapshot path: %s: %w","messagePattern":"invalid snapshot path: (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"v3.go","lineNumber":124,"sourceCode":"\treturn fmt.Sprintf(\"%08x_%08x.wal.lz4\", index, offset)\n}\n\nvar (\n\tsnapshotRegexV3   = regexp.MustCompile(`^([0-9a-f]{8})\\.snapshot\\.lz4$`)\n\twalSegmentRegexV3 = regexp.MustCompile(`^([0-9a-f]{8})_([0-9a-f]{8,16})\\.wal\\.lz4$`)\n\tgenerationRegexV3 = regexp.MustCompile(`^[0-9a-f]{16}$`)\n)\n\n// ParseSnapshotFilenameV3 parses a v0.3.x snapshot filename and returns the index.\n// 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)","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/v3.go#L106-L142","documentation":"After the v0.3.x snapshot filename matches the regex, ParseSnapshotFilenameV3 parses the captured index substring as a 32-bit hexadecimal integer with strconv.ParseInt. This error wraps that parse failure. It is rare in practice because the regex already restricts the capture to hex digits, but it guards against values overflowing a 32-bit int or other strconv failures.","triggerScenarios":"Calling ParseSnapshotFilenameV3 on a platform where int is 32 bits with a hex index larger than 0x7FFFFFFF, or any internal case where the regex-matched hex string cannot be converted via ParseInt(m[1], 16, 32).","commonSituations":"Snapshots created with an index beyond 2^31 on 32-bit platforms (rare; only after ~2 billion WAL rotations); defensive code path that developers essentially never hit directly.","solutions":["On 32-bit platforms, check the snapshot index magnitude; indexes above 0x7FFFFFFF cannot be represented and need a 64-bit build.","Verify the filename was not modified after creation; a valid v0.3.x snapshot index is at most 8 hex digits like 'ffffffff.snapshot.lz4'.","If this occurs, report it as it indicates a filename that passed the regex but overflows ParseInt's 32-bit bitSize."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"func snapshotIndexFits32Bit(hexIdx string) bool {\n    v, err := strconv.ParseInt(hexIdx, 16, 64)\n    return err == nil && v >= 0 && v <= math.MaxInt32\n}","typeGuard":"func fitsInt32(v int64) bool { return v >= math.MinInt32 && v <= math.MaxInt32 }","tryCatchPattern":"idx, err := litestream.ParseSnapshotFilenameV3(name)\nvar rangeErr *strconv.NumError\nif errors.As(err, &rangeErr) {\n    return rebuildOn64BitPlatform()\n}","preventionTips":["Run parsing tooling on 64-bit platforms (amd64/arm64)","Treat indexes above 0x7FFFFFFF as suspicious and re-snapshot","Prefer the library's own format functions to hand-built filenames"],"tags":["integer-overflow","hex-parsing","v0-3-migration"],"backgroundTag":"value-out-of-range","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"}