valyala/fasthttp · error

must implement readat

Error message

must implement readat

What it means

This Read path on fs.go requires random-access reads, so it type-asserts the underlying file to io.ReaderAt. When ff.f does not implement ReadAt, it returns 'must implement readat'. The library cannot serve positional reads without ReadAt support.

Source

Thrown at fs.go:845

	r.startPos = startPos
	r.endPos = endPos + 1
	return nil
}

func (r *fsSmallFileReader) Read(p []byte) (int, error) {
	tailLen := r.endPos - r.startPos
	if tailLen <= 0 {
		return 0, io.EOF
	}
	if len(p) > tailLen {
		p = p[:tailLen]
	}

	ff := r.ff
	if ff.f != nil {
		ra, ok := ff.f.(io.ReaderAt)
		if !ok {
			return 0, errors.New("must implement readat")
		}
		n, err := ra.ReadAt(p, int64(r.startPos))
		r.startPos += n
		return n, err
	}

	n := copy(p, ff.dirIndex[r.startPos:])
	r.startPos += n
	return n, nil
}

func (r *fsSmallFileReader) WriteTo(w io.Writer) (int64, error) {
	ff := r.ff

	var n int
	var err error
	if ff.f == nil {
		n, err = w.Write(ff.dirIndex[r.startPos:r.endPos])

View on GitHub (pinned to c96f600972)

Solutions

  1. Implement io.ReaderAt on the type stored in ff.f (back it with a real file, buffer, or memory)
  2. Use an *os.File or bytes.Reader, which already implement ReaderAt
  3. Serve non-ReaderAt sources via a plain io.Copy in your own handler instead of fasthttp's fs file cache
  4. Check that the file wasn't replaced by a streaming (compressed/decompressed) reader lacking ReadAt

Example fix

// before
func (f *streamFile) Read(p []byte) (int, error) { return f.rc.Read(p) }
// after
func (f *streamFile) ReadAt(p []byte, off int64) (int, error) {
    // implement positional read, e.g. seek to off on a temp file
    return f.tmp.ReadAt(p, off)
}
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := ff.f.(io.ReaderAt); !ok {
    return errors.New("underlying file must implement io.ReaderAt for this read path")
}

Type guard

func isReaderAt(f any) bool {
    _, ok := f.(io.ReaderAt)
    return ok
}

Try / catch

n, err := file.Read(buf)
if err != nil && strings.Contains(err.Error(), "must implement readat") {
    // fall back to a sequential io.Copy-based handler
}

Prevention

When it happens

Trigger: Calling the Read method at fs.go:845 (a startPos-tracking reader around fsFile) when the underlying ff.f is a non-ReaderAt file, such as a streaming reader or custom fs.File implementation.

Common situations: Custom fs.File wrappers (e.g. wrapping an S3 stream, pipe, or net.Conn) passed to fasthttp's request handler serving static files; content streamed from a remote source instead of an *os.File.

Related errors


AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31). Data as JSON: /api/errors/e9f5d58ac5ccb339. Report an issue: GitHub.