valyala/fasthttp · info

directory index required

Error message

directory index required

What it means

errDirIndexRequired signals that the requested path resolved to a directory and fasthttp must generate (and possibly cache) a directory index listing instead of serving a file. It is an internal sentinel used to redirect control flow into createDirIndex.

Source

Thrown at fs.go:1564

			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{}

	base := ctx.URI()

	// io/fs doesn't support ReadDir with empty path.
	if dirPath == "" {
		dirPath = "."
	}

	basePathEscaped := html.EscapeString(string(base.Path()))
	_, _ = fmt.Fprintf(w, "<html><head><title>%s</title><style>.dir { font-weight: bold }</style></head><body>", basePathEscaped)
	_, _ = fmt.Fprintf(w, "<h1>%s</h1>", basePathEscaped)
	_, _ = fmt.Fprintf(w, "<ul>")

View on GitHub (pinned to c96f600972)

Solutions

  1. Point the request at a concrete file, or add an index file (index.html) to the directory
  2. Set IndexNames on fs.Handler (e.g. fs.IndexNames = []string{"index.html"}) so directories resolve to index files
  3. Allow index generation (GenerateIndexPages=true) so fasthttp can build the listing
  4. Handle/inspect the sentinel if you embed fs internals and call serveFile directly

Example fix

// before
h := &fasthttp.Fs{Root: "./static"} // directory hits produce generated index
// after
h := &fasthttp.Fs{Root: "./static", IndexNames: []string{"index.html"}, GenerateIndexPages: true}
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(fsPath)
if err == nil && info.IsDir() {
    // ensure an index file exists or generation is enabled
}

Type guard

func isDirIndexSentinel(err error) bool {
    return err != nil && err.Error() == "directory index required"
}

Try / catch

if err := handler(ctx); err != nil && errors.Is(err, fasthttp.ErrDirIndexRequiredLike) {
    // handle directory case explicitly
}

Prevention

When it happens

Trigger: An fsHandler RequestHandler receives a URI whose fsPath maps to a directory and no index/default file applies, so serveFile returns this sentinel and the handler builds the directory listing.

Common situations: Requesting a directory URL without trailing index file; misconfigured Root pointing at a directory; Compress/GenerateIndexPages interplay causing index generation paths.

Related errors


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