gohugoio/hugo · error
failed to resolve output path
Error message
failed to resolve output path %q: %w
What it means
In copyContentDirsForOutput (convert.go:222-225), filepath.Abs(c.outputDir) converts the user-provided output directory to an absolute path. If this fails — typically because the current working directory cannot be determined — the error is wrapped with the output path.
Solutions
- Provide a valid absolute --output path so filepath.Abs is a no-op
- Ensure the current working directory exists and is accessible
- Check the --output value for invalid path characters
Example fix
# before: cwd may be unavailable hugo convert toYAML --output converted # after: absolute path hugo convert toYAML --output /home/user/converted
Defensive patterns
Strategy: validation
Validate before calling
// Resolve the output path to absolute and verify accessibility beforehand.
func resolveOutputPath(dir string) (string, error) {
abs, err := filepath.Abs(dir)
if err != nil {
return "", fmt.Errorf("failed to resolve output path %q: %w", dir, err)
}
return abs, os.MkdirAll(abs, 0o755)
} Prevention
- Provide an absolute --output path to avoid cwd-dependency
- Ensure the current working directory exists and is accessible
- Avoid path characters invalid on the target OS
When it happens
Trigger: The --output value cannot be made absolute, usually because os.Getwd fails (deleted cwd, permission denied on a parent), or the path contains invalid characters for the platform.
Common situations: Current working directory was deleted while Hugo runs; permission issues traversing the path to root; exotic/invalid path characters on Windows.
Related errors
- failed to copy to
- failed to save file
- already exists
- already exists and is not empty. See --force.
- already exists but not a directory
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/80d2dc243e728636.
Report an issue: GitHub.
Appendix: source
Thrown at commands/convert.go:224
contentDirs := make(map[string]bool)
for _, p := range pagesBackedByFile {
filename := p.File().Filename()
contentDir := strings.TrimSuffix(filename, p.File().Path())
if contentDir == filename {
continue
}
contentDirs[filepath.Clean(contentDir)] = true
}
var contentDirList []string
for contentDir := range contentDirs {
contentDirList = append(contentDirList, contentDir)
}
slices.Sort(contentDirList)
outputDirAbs, err := filepath.Abs(c.outputDir)
if err != nil {
return fmt.Errorf("failed to resolve output path %q: %w", c.outputDir, err)
}
for _, contentDir := range contentDirList {
outputContentDirAbs := filepath.Join(outputDirAbs, filepath.Base(contentDir))
skipDirs := make(map[string]bool)
relToOutputDir, err := filepath.Rel(contentDir, outputDirAbs)
if err == nil && relToOutputDir != ".." && !strings.HasPrefix(relToOutputDir, ".."+string(filepath.Separator)) {
skipDirs[filepath.Clean(outputDirAbs)] = true
}
relToOutputContentDir, err := filepath.Rel(contentDir, outputContentDirAbs)
if err == nil && relToOutputContentDir != ".." && !strings.HasPrefix(relToOutputContentDir, ".."+string(filepath.Separator)) {
skipDirs[filepath.Clean(outputContentDirAbs)] = true
}
var shouldCopy func(filename string) bool
if len(skipDirs) > 0 {
shouldCopy = func(filename string) bool {View on GitHub (pinned to 52c9bd7908)