{"record":{"id":"e01776c22d4d42be","repo":"gohugoio/hugo","slug":"decorate-w","errorCode":null,"errorMessage":"decorate: %w","messagePattern":"decorate: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hugofs/decorators.go","lineNumber":158,"sourceCode":"}\n\nfunc (l *baseFileDecoratorFile) ReadDir(n int) ([]fs.DirEntry, error) {\n\tfis, err := l.File.(fs.ReadDirFile).ReadDir(-1)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfisp := make([]fs.DirEntry, len(fis))\n\n\tfor i, fi := range fis {\n\t\tfilename := fi.Name()\n\t\tif l.Name() != \"\" {\n\t\t\tfilename = filepath.Join(l.Name(), fi.Name())\n\t\t}\n\n\t\tfid, err := l.fs.decorate(fi, filename)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"decorate: %w\", err)\n\t\t}\n\n\t\tfisp[i] = fid.(fs.DirEntry)\n\n\t}\n\n\treturn fisp, err\n}\n\nfunc (l *baseFileDecoratorFile) Readdir(c int) (ofi []os.FileInfo, err error) {\n\tpanic(\"not supported: Use ReadDir\")\n}\n","sourceCodeStart":140,"sourceCodeEnd":171,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/hugofs/decorators.go#L140-L171","documentation":"Thrown by baseFileDecoratorFile.ReadDir in hugofs when the per-entry decorator fails while listing a directory. The decorator (set via NewBaseFileDecorator or decorateDirs) attaches metadata such as the real filename and an opener closure to each returned DirEntry; if that closure errors the whole ReadDir aborts. It wraps the underlying decorator error with 'decorate: %w'.","triggerScenarios":"Calling ReadDir (or Readdir-style traversal) on a filesystem produced by NewBaseFileDecorator whose decorate func returns an error — most commonly because an inner fs.Stat/join in a custom JoinStatFunc failed, or a callback-based decorator rejected an entry. Surfaces indirectly when Hugo walks project/content mounts via hugofs.","commonSituations":"A custom afero.Fs wrapped by NewBaseFileDecorator whose backing store becomes unavailable (network/overlay mount dropped, permission revoked on a subpath), symlink targets removed mid-build, or a decorator callback that Stat's a joined path that no longer exists. Rare in stock Hugo; common when embedding Hugo's hugofs in another tool with a custom decorator.","solutions":["Inspect the wrapped error (errors.Unwrap / %w chain) to find which entry and which decorator op failed.","If using a custom decorator/callback, make its Stat/JoinStatFunc tolerant of missing targets or return the raw entry instead of erroring.","Verify the underlying afero.Fs still resolves the directory's children (call fs.Stat on the failing child path directly).","Ensure no concurrent mutation removes files during the ReadDir iteration (Hugo file watching can rename temp files)."],"exampleFix":"// before\ndecorator := func(fi FileNameIsDir, name string) (FileNameIsDir, error) {\n    joined, err := fs.Stat(filepath.Join(base, name))\n    if err != nil {\n        return nil, err // bubbles up as \"decorate: %w\"\n    }\n    return joined, nil\n}\n// after\ndecorator := func(fi FileNameIsDir, name string) (FileNameIsDir, error) {\n    joined, err := fs.Stat(filepath.Join(base, name))\n    if err != nil {\n        return fi, nil // fall back to the original entry\n    }\n    return joined, nil\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"fis, err := decoratedFs.(fs.ReadDirFile).ReadDir(-1)\nif err != nil {\n    var decErr *fs.PathError\n    if errors.As(err, &decErr) || strings.Contains(err.Error(), \"decorate:\") {\n        // fall back to the unwrapped fs to enumerate entries without decoration\n        fis, err = unwrap(decoratedFs).ReadDir(-1)\n    }\n    if err != nil { return err }\n}","preventionTips":["Keep decorator closures total: never error on a single bad entry, fall back to the raw entry.","Do not mutate the underlying filesystem during ReadDir (pause watchers/syncs).","Pin decorator Stat/JoinStatFuncs to return the original entry on transient errors."],"tags":["filesystem","hugofs","decorator","readdir"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}