{"record":{"id":"987f8fd8d190e995","repo":"valyala/fasthttp","slug":"directory-index-required","errorCode":null,"errorMessage":"directory index required","messagePattern":"directory index required","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"fs.go","lineNumber":1564,"sourceCode":"\t\t\tctx.Logger().Printf(\"insufficient permissions for saving compressed file for %q. Serving uncompressed file. \"+\n\t\t\t\t\"Allow write access to the directory with this file in order to improve fasthttp performance\", indexFilePath)\n\t\t\tmustCompress = false\n\t\t\treturn h.openFSFile(indexFilePath, mustCompress, fileEncoding)\n\t\t}\n\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, fmt.Errorf(\"cannot open file %q: %w\", indexFilePath, err)\n\t\t}\n\t}\n\n\tif !h.generateIndexPages {\n\t\treturn nil, fmt.Errorf(\"cannot access directory without index page: directory %q\", dirPath)\n\t}\n\n\treturn h.createDirIndex(ctx, dirPath, mustCompress, fileEncoding)\n}\n\nvar (\n\terrDirIndexRequired   = errors.New(\"directory index required\")\n\terrNoCreatePermission = errors.New(\"no 'create file' permissions\")\n)\n\nfunc (h *fsHandler) createDirIndex(ctx *RequestCtx, dirPath string, mustCompress bool, fileEncoding string) (*fsFile, error) {\n\tw := &bytebufferpool.ByteBuffer{}\n\n\tbase := ctx.URI()\n\n\t// io/fs doesn't support ReadDir with empty path.\n\tif dirPath == \"\" {\n\t\tdirPath = \".\"\n\t}\n\n\tbasePathEscaped := html.EscapeString(string(base.Path()))\n\t_, _ = fmt.Fprintf(w, \"<html><head><title>%s</title><style>.dir { font-weight: bold }</style></head><body>\", basePathEscaped)\n\t_, _ = fmt.Fprintf(w, \"<h1>%s</h1>\", basePathEscaped)\n\t_, _ = fmt.Fprintf(w, \"<ul>\")\n","sourceCodeStart":1546,"sourceCodeEnd":1582,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/fs.go#L1546-L1582","documentation":"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.","triggerScenarios":"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.","commonSituations":"Requesting a directory URL without trailing index file; misconfigured Root pointing at a directory; Compress/GenerateIndexPages interplay causing index generation paths.","solutions":["Point the request at a concrete file, or add an index file (index.html) to the directory","Set IndexNames on fs.Handler (e.g. fs.IndexNames = []string{\"index.html\"}) so directories resolve to index files","Allow index generation (GenerateIndexPages=true) so fasthttp can build the listing","Handle/inspect the sentinel if you embed fs internals and call serveFile directly"],"exampleFix":"// before\nh := &fasthttp.Fs{Root: \"./static\"} // directory hits produce generated index\n// after\nh := &fasthttp.Fs{Root: \"./static\", IndexNames: []string{\"index.html\"}, GenerateIndexPages: true}","handlingStrategy":"validation","validationCode":"info, err := os.Stat(fsPath)\nif err == nil && info.IsDir() {\n    // ensure an index file exists or generation is enabled\n}","typeGuard":"func isDirIndexSentinel(err error) bool {\n    return err != nil && err.Error() == \"directory index required\"\n}","tryCatchPattern":"if err := handler(ctx); err != nil && errors.Is(err, fasthttp.ErrDirIndexRequiredLike) {\n    // handle directory case explicitly\n}","preventionTips":["Always ship an index.html in served directories and list it in fs.IndexNames","Set GenerateIndexPages=true if directory listings are acceptable","Never point Root at an empty directory in production","Sanity-check the URI-to-path mapping in custom path rewriters"],"tags":["go","fasthttp","filesystem","directory-listing"],"backgroundTag":"directory-index-required","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}