{"record":{"id":"be14d5423a47aebd","repo":"benbjohnson/litestream","slug":"invalid-wal-segment-path-s-w","errorCode":null,"errorMessage":"invalid wal segment path: %s: %w","messagePattern":"invalid wal segment path: (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"v3.go","lineNumber":138,"sourceCode":"\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.\n// ReplicaClient implementations that support v0.3.x restore should implement this interface.\ntype ReplicaClientV3 interface {\n\t// GenerationsV3 returns a list of generation IDs in the replica.\n\t// Returns an empty slice if no v0.3.x backups exist.","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/v3.go#L120-L156","documentation":"In ParseWALSegmentFilenameV3, once the filename matches the regex, the first capture (WAL index) is parsed with strconv.ParseInt(m[1], 16, 32). This error wraps a failure of that conversion. It can only fire when the matched hex string cannot be represented in a 32-bit signed integer, since the regex guarantees hex digits.","triggerScenarios":"Parsing a WAL segment whose 8-hex-digit index exceeds 0x7FFFFFFF on a platform where int is 32 bits; ParseInt(m[1], 16, 32) returns a range error which is wrapped here.","commonSituations":"32-bit builds (arm, 386) processing replicas with very high WAL indexes; essentially unreachable on 64-bit platforms.","solutions":["Run Litestream/tooling on a 64-bit platform (amd64, arm64) so int can hold indexes up to 0xFFFFFFFF.","Check that the segment filename was not tampered with; genuine v0.3.x indexes stay within 8 hex digits.","If you must support 32-bit, parse the index yourself with ParseInt(m[1], 16, 64) before calling the library."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"func walIndexFits32Bit(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, off, err := litestream.ParseWALSegmentFilenameV3(name)\nvar numErr *strconv.NumError\nif errors.As(err, &numErr) && errors.Is(numErr.Err, strconv.ErrRange) {\n    return switchTo64BitRuntime()\n}","preventionTips":["Build/parse on 64-bit platforms","Cap replica scanning at segments with indexes within int32 range on 32-bit hosts","Validate hex index magnitude before invoking the parser on 32-bit systems"],"tags":["integer-overflow","hex-parsing","wal"],"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"}