valyala/fasthttp · error

cannot open file

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.

Solutions

  1. Log the wrapped inner error to see the real errno (EACCES vs EISDIR)
  2. Fix permissions: chmod/chown index.html so the fasthttp process can read it
  3. Ensure the path is a regular file, not a directory: ls -la the directory and rename/remove the conflicting entry
  4. 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

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


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

Appendix: 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)