AlistGo/alist · error

offset out of range

Error message

offset out of range

What it means

When a stream cannot be memory-mapped, RangeReadReadAtSeeker is used and its RangeRead method validates the requested start offset: it must be within [0, size]. An offset beyond the stream size (or negative) returns 'offset out of range' before any network read is attempted. This is a local sanity check, so it fails instantly rather than after a round trip.

Source

Thrown at internal/stream/stream.go:432

		r.ss.Closers.Add(r.headCache)
	}
}

func NewReadAtSeeker(ss *SeekableStream, offset int64, forceRange ...bool) (SStreamReadAtSeeker, error) {
	if ss.mFile != nil {
		_, err := ss.mFile.Seek(offset, io.SeekStart)
		if err != nil {
			return nil, err
		}
		return &FileReadAtSeeker{ss: ss}, nil
	}
	r := &RangeReadReadAtSeeker{
		ss:        ss,
		masterOff: offset,
	}
	if offset != 0 || utils.IsBool(forceRange...) {
		if offset < 0 || offset > ss.GetSize() {
			return nil, errors.New("offset out of range")
		}
		_, err := r.getReaderAtOffset(offset)
		if err != nil {
			return nil, err
		}
	} else {
		rc := &readerCur{reader: ss, cur: offset}
		r.readers = append(r.readers, rc)
	}
	return r, nil
}

func NewMultiReaderAt(ss []*SeekableStream) (readerutil.SizeReaderAt, error) {
	readers := make([]readerutil.SizeReaderAt, 0, len(ss))
	for _, s := range ss {
		ra, err := NewReadAtSeeker(s, 0)
		if err != nil {
			return nil, err

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Re-validate the offset against the current stream size before reading
  2. Refresh the cached listing/size for the object and retry
  3. Fix client-side range math, especially end-anchored ranges (bytes=-N) converted to absolute offsets

Example fix

// before
r, err := ss.RangeRead(offset, length)
// after
if offset < 0 || offset > ss.GetSize() {
    return nil, fmt.Errorf("bad offset %d for size %d", offset, ss.GetSize())
}
r, err := ss.RangeRead(offset, length)
Defensive patterns

Strategy: validation

Validate before calling

// Before a ranged read
size := ss.GetSize()
if offset < 0 || offset > size {
    return fmt.Errorf("offset %d out of range for size %d", offset, size)
}

Type guard

func validOffset(off int64, size int64) bool {
    return off >= 0 && off <= size
}

Try / catch

r, err := ss.RangeRead(offset, length)
if err != nil && strings.Contains(err.Error(), "offset out of range") {
    // refresh cached size metadata and recompute the range
    refreshListing()
}

Prevention

When it happens

Trigger: Calling the stream's RangeRead/section reader with an offset > ss.GetSize() or < 0 — e.g. a client sending a Range header like 'bytes=999999999999-' on a smaller file, or code computing an offset from stale size metadata.

Common situations: Cached file size is smaller than the real file (stale listing) so a valid-looking seek exceeds the cached bound; clients issuing end-anchored ranges computed incorrectly; off-by-one after truncation.

Related errors


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/69655c7f863720ea. Report an issue: GitHub.