{"record":{"id":"b3ee99a08c70f84d","repo":"gohugoio/hugo","slug":"s-q","errorCode":null,"errorMessage":"%s: %q","messagePattern":"%s: %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/collect.go","lineNumber":835,"sourceCode":"\n\t\tif !owner.projectMod && !filepath.IsLocal(mnt.Source) {\n\t\t\treturn nil, fmt.Errorf(\"%s: %q: mount source must be a local path for modules/themes\", errMsg, mnt.Source)\n\t\t}\n\t\tif filepath.IsAbs(mnt.Source) {\n\t\t\t// Abs paths in the main project is allowed.\n\t\t\tsourceDir = mnt.Source\n\t\t} else {\n\t\t\tsourceDir = filepath.Join(dir, mnt.Source)\n\t\t}\n\n\t\t// Verify that Source exists\n\t\t_, err := c.fs.Stat(sourceDir)\n\t\tif err != nil {\n\t\t\tif paths.IsSameFilePath(sourceDir, c.ccfg.PublishDir) {\n\t\t\t\t// This is a little exotic, but there are use cases for mounting the public folder.\n\t\t\t\t// This will typically also be in .gitingore, so create it.\n\t\t\t\tif err := c.fs.MkdirAll(sourceDir, 0o755); err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"%s: %q\", errMsg, err)\n\t\t\t\t}\n\t\t\t} else if strings.HasSuffix(sourceDir, files.FilenameHugoStatsJSON) {\n\t\t\t\t// A common pattern for Tailwind 3 is to mount that file to get it on the server watch list.\n\n\t\t\t\t// A common pattern is also to add hugo_stats.json to .gitignore.\n\n\t\t\t\t// Create an empty file.\n\t\t\t\tf, err := c.fs.Create(sourceDir)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"%s: %q\", errMsg, err)\n\t\t\t\t}\n\t\t\t\tf.Close()\n\t\t\t} else {\n\t\t\t\tif isModuleNodeModulesImport {\n\t\t\t\t\t// A module imported a path inside node_modules, but it didn't exist.\n\t\t\t\t\t// Make this a special case and also try relative to the project root.\n\t\t\t\t\tsourceDir = filepath.Join(c.ccfg.WorkingDir, mnt.Source)\n\t\t\t\t\t_, err := c.fs.Stat(sourceDir)","sourceCodeStart":817,"sourceCodeEnd":853,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/modules/collect.go#L817-L853","documentation":"normalizeMounts has a carve-out: if a mount source resolves to the project's PublishDir, Hugo will MkdirAll it (since it's typically gitignored). If that MkdirAll fails, the underlying fs error is wrapped. So the error is really 'could not create the publish/public directory for a mount that targets it.'","triggerScenarios":"A mount whose source equals PublishDir (e.g. mounting `public/` to observe rendered output) on a filesystem where MkdirAll fails — read-only FS, permission denied, disk full, or a parent path that exists as a file.","commonSituations":"Hugo running in a read-only container layer, CI workspace with restricted write permissions, or a misconfigured publishDir whose parent is a file.","solutions":["Grant write access to the publishDir path (and parents) for the Hugo process user.","If read-only by design, do not mount the publishDir, or pre-create it with correct perms.","Check the publishDir setting in config isn't pointing somewhere unwritable.","In containers, mount a writable volume at the publishDir."],"exampleFix":"// before: read-only publishDir mount fails\n// after: pre-create with perms or use a writable volume\nmkdir -p public && chmod u+w public\nhugo","handlingStrategy":"validation","validationCode":"// Ensure the publishDir is writable before build\nimport \"os\"\n\nfunc ensurePublishDirWritable(publishDir string) error {\n  if err := os.MkdirAll(publishDir, 0o755); err != nil {\n    return fmt.Errorf(\"publishDir not writable: %w\", err)\n  }\n  probe := filepath.Join(publishDir, \".hugowrite\")\n  if err := os.WriteFile(probe, []byte(\"x\"), 0o644); err != nil { return err }\n  return os.Remove(probe)\n}","typeGuard":"null","tryCatchPattern":"// On mount-MkdirAll failure, check publishDir perms or remove the publishDir mount.","preventionTips":["Grant write access to publishDir for the Hugo process user.","Avoid read-only filesystems when mounting publishDir.","Pre-create publishDir in setup scripts."],"tags":["modules","mounts","filesystem","permissions","hugo-module"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}