benbjohnson/litestream · warning

invalid wal segment path: %s: %w

Error message

invalid wal segment path: %s: %w

What it means

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.

Source

Thrown at v3.go:138

		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.
// ReplicaClient implementations that support v0.3.x restore should implement this interface.
type ReplicaClientV3 interface {
	// GenerationsV3 returns a list of generation IDs in the replica.
	// Returns an empty slice if no v0.3.x backups exist.

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Run Litestream/tooling on a 64-bit platform (amd64, arm64) so int can hold indexes up to 0xFFFFFFFF.
  2. Check that the segment filename was not tampered with; genuine v0.3.x indexes stay within 8 hex digits.
  3. If you must support 32-bit, parse the index yourself with ParseInt(m[1], 16, 64) before calling the library.
Defensive patterns

Strategy: type-guard

Validate before calling

func walIndexFits32Bit(hexIdx string) bool {
    v, err := strconv.ParseInt(hexIdx, 16, 64)
    return err == nil && v >= 0 && v <= math.MaxInt32
}

Type guard

func fitsInt32(v int64) bool { return v >= math.MinInt32 && v <= math.MaxInt32 }

Try / catch

idx, off, err := litestream.ParseWALSegmentFilenameV3(name)
var numErr *strconv.NumError
if errors.As(err, &numErr) && errors.Is(numErr.Err, strconv.ErrRange) {
    return switchTo64BitRuntime()
}

Prevention

When it happens

Trigger: 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.

Common situations: 32-bit builds (arm, 386) processing replicas with very high WAL indexes; essentially unreachable on 64-bit platforms.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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