{"id":"1c67356deb73a8bf","repo":"gohugoio/hugo","slug":"errnoop","errorCode":"errNoOp","errorMessage":"this operation is not supported","messagePattern":"this operation is not supported","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"hugofs/noop_fs.go","lineNumber":25,"sourceCode":"//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage hugofs\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/spf13/afero\"\n)\n\nvar (\n\terrNoOp          = errors.New(\"this operation is not supported\")\n\t_       afero.Fs = (*noOpFs)(nil)\n\n\t// NoOpFs provides a no-op filesystem that implements the afero.Fs\n\t// interface.\n\tNoOpFs = &noOpFs{}\n)\n\ntype noOpFs struct{}\n\nfunc (fs noOpFs) Create(name string) (afero.File, error) {\n\tpanic(errNoOp)\n}\n\nfunc (fs noOpFs) Mkdir(name string, perm os.FileMode) error {\n\treturn nil\n}\n\nfunc (fs noOpFs) MkdirAll(path string, perm os.FileMode) error {","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/hugofs/noop_fs.go#L7-L43","documentation":"Hugo's `hugofs.NoOpFs` is a stub afero.Fs used where a real filesystem must not be touched (e.g. read-only or placeholder mounts). Read-style calls return os.ErrNotExist, but mutating operations like Create, Rename, Chmod, Chtimes and Chown panic with errNoOp because reaching them indicates a code path is trying to write through a filesystem that was explicitly wired to do nothing.","triggerScenarios":"Calling Create, Rename, Chmod, Chtimes or Chown on hugofs.NoOpFs, or any Read/Write/Seek/Readdir on a file backed by noOpRegularFileOps (hugofs/noop_fs.go:35-129). It is a panic, not a returned error.","commonSituations":"Custom Hugo tooling or a module/mount misconfiguration that routes a writable target (publishDir, cache dir) to a NoOpFs-backed composite filesystem; plugin/fork code passing the wrong afero.Fs into a component that later writes.","solutions":["Find the panicking call site in the stack trace and identify which component received NoOpFs instead of a real filesystem.","Wire the correct writable Fs (e.g. the OS or destination filesystem) into that component instead of NoOpFs.","If the operation is genuinely optional in a no-op context, guard the call so mutating operations are skipped for NoOpFs."],"exampleFix":"// before\nfs := hugofs.NoOpFs\nf, _ := fs.Create(\"out.txt\") // panics: this operation is not supported\n// after\nfs := afero.NewOsFs()\nf, err := fs.Create(\"out.txt\")","handlingStrategy":"type-guard","validationCode":"// Don't pass a noop/stub Fs where real IO is needed\nif _, ok := fs.(interface{ Name() string }); ok && fs.Name() == \"noopFs\" {\n    return fmt.Errorf(\"filesystem is a no-op stub; configure a real Fs\")\n}","typeGuard":"func isNoopFs(fs afero.Fs) bool {\n    return fs == nil || fs.Name() == \"noopFs\"\n}","tryCatchPattern":"if err := doFsOp(fs); err != nil {\n    if strings.Contains(err.Error(), \"operation is not supported\") {\n        return fmt.Errorf(\"fs %q does not support this operation: %w\", fs.Name(), err)\n    }\n    return err\n}","preventionTips":["Only call read/write operations on filesystems you constructed with real backing (afero.NewOsFs, hugofs.Os)","Treat hugofs.NoOpFs as a sentinel for disabled features (e.g. publishing disabled) and branch before doing IO","Check which Fs a Hugo deps/config wires in (SourceFs vs PublishFs) before performing operations on it"],"tags":["filesystem","panic","afero","hugo-internal"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}