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

  1. 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.
  2. Verify the process user has read+execute (r+x) permission on every directory component of the path.
  3. If serving from a network/FUSE mount, ensure the mount is healthy and Stat is supported.
  4. 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

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


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