valyala/fasthttp · error
cannot obtain info for file %q: %w
Error message
cannot obtain info for file %q: %w
What it means
This error is returned by the fasthttp filesystem handler (fsHandler) when os.Stat (via fs.File.Stat) fails on an original file it just opened, before compression/caching. The library needs file metadata (size, modtime, IsDir) to decide whether to serve, compress, or cache the file; without it the file cannot be handled. The original file handle is closed before returning, and the underlying OS error is wrapped in %w.
Source
Thrown at fs.go:1682
}
return ff, nil
}
const (
fsMinCompressRatio = 0.8
fsMaxCompressibleFileSize = 8 * 1024 * 1024
)
func (h *fsHandler) compressAndOpenFSFile(filePath, fileEncoding string) (*fsFile, error) {
f, err := h.filesystem.Open(filePath)
if err != nil {
return nil, err
}
fileInfo, err := f.Stat()
if err != nil {
_ = f.Close()
return nil, fmt.Errorf("cannot obtain info for file %q: %w", filePath, err)
}
if fileInfo.IsDir() {
_ = f.Close()
return nil, errDirIndexRequired
}
if strings.HasSuffix(filePath, h.compressedFileSuffixes[fileEncoding]) ||
fileInfo.Size() > fsMaxCompressibleFileSize ||
!isFileCompressible(f, fsMinCompressRatio) {
return h.newFSFile(f, fileInfo, false, filePath, "")
}
compressedFilePath := h.filePathToCompressed(filePath)
if _, ok := h.filesystem.(*osFS); !ok {
return h.newCompressedFSFileCache(f, fileInfo, compressedFilePath, fileEncoding)
}View on GitHub (pinned to c96f600972)
Solutions
- Check the wrapped cause (errors.Is/As on the %w error) — if it is fs.ErrNotExist, the file was removed concurrently; re-check your file lifecycle or disable aggressive deletion.
- Verify the process user has read+execute (r+x) permission on every directory component of the path.
- If serving from a network/FUSE mount, ensure the mount is healthy and Stat is supported.
- Retry the request: this is often transient if caused by a concurrent rename/delete.
Example fix
// before (handler side, file disappearing under load)
fs := &fasthttp.FS{Root: "./static"}
// after (guard the file exists and is readable before serving)
if _, err := os.Stat("./static/" + name); err != nil {
ctx.Error("file unavailable", fasthttp.StatusNotFound)
return
}
fsHandler.NewRequestHandler()(ctx) Defensive patterns
Strategy: retry
Validate before calling
if fi, err := os.Stat(path); err != nil || fi.IsDir() {
// skip serving / return 404 before calling the handler
} Type guard
func isStatErr(err error) bool { return strings.Contains(err.Error(), "cannot obtain info for file") } Try / catch
if err := handler(ctx); err != nil && strings.Contains(err.Error(), "cannot obtain info for file") {
ctx.Error("file unavailable", fasthttp.StatusNotFound) // or retry once
} Prevention
- Avoid deleting files while the server serves them; use atomic rename-on-replace.
- Ensure the service user has r+x on all path components.
- Prefer local disks over flaky network mounts for static roots.
When it happens
Trigger: Calling fasthttp's FS handler / RequestCtx.SendFile / ServeFile with a path that resolves to a file that exists at open time but whose Stat fails: file deleted between Open and Stat, permission revoked on parent directory, or a filesystem (e.g. FUSE/NFS) whose Stat errors.
Common situations: Race where a file is removed while the static file server is serving it; running the server as a user lacking execute permission on a parent directory; network mounts (NFS) returning ESTALE; serving from an overlay/FUSE filesystem with flaky Stat.
Related errors
- cannot obtain info for compressed file %q: %w
- must implement seek
- must implement readat
- directory index required
- no 'create file' permissions
AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31).
Data as JSON: /api/errors/258f317468601e38.
Report an issue: GitHub.