valyala/fasthttp · error
cannot open file %q: %w
Error message
cannot open file %q: %w
What it means
openIndexFile tries to open a pre-compressed or cached index file (e.g. index.html.gz) before falling back to the real index. If opening that index file fails for a reason other than fs.ErrNotExist (e.g. EACCES, EISDIR), the error is wrapped and returned rather than silently falling back.
Source
Thrown at fs.go:1552
func (h *fsHandler) openIndexFile(ctx *RequestCtx, dirPath string, mustCompress bool, fileEncoding string) (*fsFile, error) {
for _, indexName := range h.indexNames {
indexFilePath := indexName
if dirPath != "" {
indexFilePath = dirPath + "/" + indexName
}
ff, err := h.openFSFile(indexFilePath, mustCompress, fileEncoding)
if err == nil {
return ff, nil
}
if mustCompress && err == errNoCreatePermission {
ctx.Logger().Printf("insufficient permissions for saving compressed file for %q. Serving uncompressed file. "+
"Allow write access to the directory with this file in order to improve fasthttp performance", indexFilePath)
mustCompress = false
return h.openFSFile(indexFilePath, mustCompress, fileEncoding)
}
if !errors.Is(err, fs.ErrNotExist) {
return nil, fmt.Errorf("cannot open file %q: %w", indexFilePath, err)
}
}
if !h.generateIndexPages {
return nil, fmt.Errorf("cannot access directory without index page: directory %q", dirPath)
}
return h.createDirIndex(ctx, dirPath, mustCompress, fileEncoding)
}
var (
errDirIndexRequired = errors.New("directory index required")
errNoCreatePermission = errors.New("no 'create file' permissions")
)
func (h *fsHandler) createDirIndex(ctx *RequestCtx, dirPath string, mustCompress bool, fileEncoding string) (*fsFile, error) {
w := &bytebufferpool.ByteBuffer{}
View on GitHub (pinned to c96f600972)
Solutions
- Log the wrapped inner error to see the real errno (EACCES vs EISDIR)
- Fix permissions: chmod/chown index.html so the fasthttp process can read it
- Ensure the path is a regular file, not a directory: ls -la the directory and rename/remove the conflicting entry
- If you intentionally don't want index files, disable index page generation (GenerateIndexPages: false) so a clearer error is returned
Example fix
// before (server config with unreadable index)
fs.New(fs.Config{Root: "./static"}) // index.html 0600 root-owned
// after
// chmod 644 ./static/index.html && chown www-data ./static/index.html
fs.New(fs.Config{Root: "./static", GenerateIndexPages: true}) Defensive patterns
Strategy: fallback
Validate before calling
if fi, err := os.Stat(indexPath); err != nil || !fi.Mode().IsRegular() || fi.Mode().Perm()&0o400 == 0 {
log.Printf("index file %s unreadable", indexPath)
} Type guard
func readableRegularFile(path string) bool {
fi, err := os.Stat(path)
return err == nil && fi.Mode().IsRegular()
} Try / catch
if err := serveIndex(ctx, dir); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
log.Printf("index open failed: %v", err) // real errno is wrapped
}
http.Error(ctx, "not found", 404)
} Prevention
- Chown/chmod index.html to match the fasthttp process user
- Verify no directory shadows the index filename
- Include an fs health check that Stats every configured index path at startup
- Deploy files atomically with correct ownership
When it happens
Trigger: Directory request handled by fasthttp FS/FileServer where the index file path exists but cannot be opened: wrong permissions on index.html, index path is actually a directory, or an I/O error; also compressed-file paths with unreadable ACLs.
Common situations: Deploy leaves index.html owned by root with 0600 while the server runs as another user; a file literally named like the index path but being a directory; NFS/overlayfs transient I/O errors in containers.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- no 'create file' permissions
- cannot open already opened file: %w
- cannot create temporary file for %q: %w
- must implement seek
- must implement readat
AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31).
Data as JSON: /api/errors/363f04367656839d.
Report an issue: GitHub.