{"record":{"id":"4fc95a521a80eb62","repo":"valyala/fasthttp","slug":"cannot-access-directory-without-index-page-direct","errorCode":null,"errorMessage":"cannot access directory without index page: directory %q","messagePattern":"cannot access directory without index page: directory %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"fs.go","lineNumber":1557,"sourceCode":"\t\t}\n\n\t\tff, err := h.openFSFile(indexFilePath, mustCompress, fileEncoding)\n\t\tif err == nil {\n\t\t\treturn ff, nil\n\t\t}\n\t\tif mustCompress && err == errNoCreatePermission {\n\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 = \".\"","sourceCodeStart":1539,"sourceCodeEnd":1575,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/fs.go#L1539-L1575","documentation":"The FS handler was asked to serve a directory whose index file could not be resolved, and index page generation is disabled (Config.GenerateIndexPages == false). fasthttp therefore cannot produce any representation of the directory and returns this error, which typically surfaces to the client as 403/500.","triggerScenarios":"Requesting a directory URL (e.g. GET /subdir/) against fs.New(fs.Config{... GenerateIndexPages: false ...}) when no index.html (or configured indexNames) exists in that directory; direct handler.openIndexFile calls with mustCompress contexts and no index file present.","commonSituations":"Deployments that disable generated index pages for security but forget to ship index.html into each directory; misconfigured indexNames so the real index file is never looked up; static sites where only some directories have index files.","solutions":["Ship an index file (index.html) into every servable directory, or","Set GenerateIndexPages: true if auto-generated directory listings are acceptable for your security posture","Add your actual index filename to Config.IndexNames (e.g. []string{\"index.htm\", \"default.html\"}) so it is found","Restructure URLs so users never hit bare directories (link directly to files)"],"exampleFix":"// before\nh := fs.New(fs.Config{Root: \"./static\", GenerateIndexPages: false})\n// after — either ship index.html, or allow generated listings\nh := fs.New(fs.Config{Root: \"./static\", GenerateIndexPages: true, IndexNames: []string{\"index.html\", \"index.htm\"}})","handlingStrategy":"fallback","validationCode":"cfg := fs.Config{IndexNames: []string{\"index.html\", \"index.htm\"}, GenerateIndexPages: true}\nfor _, dir := range []string{\"./static\", \"./static/sub\"} {\n    if _, err := os.Stat(filepath.Join(dir, \"index.html\")); err != nil {\n        log.Printf(\"missing index in %s\", dir)\n    }\n}","typeGuard":"func hasIndexFile(dir string, names []string) bool {\n    for _, n := range names {\n        if _, err := os.Stat(filepath.Join(dir, n)); err == nil { return true }\n    }\n    return false\n}","tryCatchPattern":"if err := fileHandler(ctx); err != nil {\n    if strings.Contains(err.Error(), \"without index page\") {\n        http.Error(ctx, \"Forbidden\", http.StatusForbidden)\n    }\n}","preventionTips":["Keep GenerateIndexPages: true unless you guarantee index files everywhere","List every real index filename in Config.IndexNames","Add a CI/build check that each servable directory contains an index file","Deep-link to files instead of directory URLs when indexes are disabled"],"tags":["config","file-server","directory-index","fasthttp"],"backgroundTag":"directory-index-disabled","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}