{"record":{"id":"e9f5d58ac5ccb339","repo":"valyala/fasthttp","slug":"must-implement-readat","errorCode":null,"errorMessage":"must implement readat","messagePattern":"must implement readat","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"fs.go","lineNumber":845,"sourceCode":"\tr.startPos = startPos\n\tr.endPos = endPos + 1\n\treturn nil\n}\n\nfunc (r *fsSmallFileReader) Read(p []byte) (int, error) {\n\ttailLen := r.endPos - r.startPos\n\tif tailLen <= 0 {\n\t\treturn 0, io.EOF\n\t}\n\tif len(p) > tailLen {\n\t\tp = p[:tailLen]\n\t}\n\n\tff := r.ff\n\tif ff.f != nil {\n\t\tra, ok := ff.f.(io.ReaderAt)\n\t\tif !ok {\n\t\t\treturn 0, errors.New(\"must implement readat\")\n\t\t}\n\t\tn, err := ra.ReadAt(p, int64(r.startPos))\n\t\tr.startPos += n\n\t\treturn n, err\n\t}\n\n\tn := copy(p, ff.dirIndex[r.startPos:])\n\tr.startPos += n\n\treturn n, nil\n}\n\nfunc (r *fsSmallFileReader) WriteTo(w io.Writer) (int64, error) {\n\tff := r.ff\n\n\tvar n int\n\tvar err error\n\tif ff.f == nil {\n\t\tn, err = w.Write(ff.dirIndex[r.startPos:r.endPos])","sourceCodeStart":827,"sourceCodeEnd":863,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/fs.go#L827-L863","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Implement io.ReaderAt on the type stored in ff.f (back it with a real file, buffer, or memory)","Use an *os.File or bytes.Reader, which already implement ReaderAt","Serve non-ReaderAt sources via a plain io.Copy in your own handler instead of fasthttp's fs file cache","Check that the file wasn't replaced by a streaming (compressed/decompressed) reader lacking ReadAt"],"exampleFix":"// before\nfunc (f *streamFile) Read(p []byte) (int, error) { return f.rc.Read(p) }\n// after\nfunc (f *streamFile) ReadAt(p []byte, off int64) (int, error) {\n    // implement positional read, e.g. seek to off on a temp file\n    return f.tmp.ReadAt(p, off)\n}","handlingStrategy":"type-guard","validationCode":"if _, ok := ff.f.(io.ReaderAt); !ok {\n    return errors.New(\"underlying file must implement io.ReaderAt for this read path\")\n}","typeGuard":"func isReaderAt(f any) bool {\n    _, ok := f.(io.ReaderAt)\n    return ok\n}","tryCatchPattern":"n, err := file.Read(buf)\nif err != nil && strings.Contains(err.Error(), \"must implement readat\") {\n    // fall back to a sequential io.Copy-based handler\n}","preventionTips":["Serve files from local storage via os.Open, which implements ReaderAt","Add ReadAt to custom file wrappers used with fasthttp","Avoid Range-request support (disable Accept-Ranges paths) for non-ReaderAt sources","Unit-test partial reads against your file implementation"],"tags":["go","fasthttp","filesystem","readerat"],"backgroundTag":"readerat-not-implemented","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}