{"id":"257165c3e35f7a53","repo":"gohugoio/hugo","slug":"failed-to-save-file-q-w","errorCode":null,"errorMessage":"failed to save file %q:: %w","messagePattern":"failed to save file %q:: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"commands/convert.go","lineNumber":199,"sourceCode":"\tif err != nil {\n\t\tsite.Log.Errorln(errMsg)\n\t\treturn err\n\t}\n\n\tnewContent.Write(pf.Content)\n\n\tnewFilename := p.File().Filename()\n\n\tif c.outputDir != \"\" {\n\t\tcontentDir := strings.TrimSuffix(newFilename, p.File().Path())\n\t\tcontentDir = filepath.Base(contentDir)\n\n\t\tnewFilename = filepath.Join(c.outputDir, contentDir, p.File().Path())\n\t}\n\n\tfs := hugofs.Os\n\tif err := helpers.WriteToDisk(newFilename, &newContent, fs); err != nil {\n\t\treturn fmt.Errorf(\"failed to save file %q:: %w\", newFilename, err)\n\t}\n\n\treturn nil\n}\n\nfunc (c *convertCommand) copyContentDirsForOutput(pagesBackedByFile page.Pages) error {\n\tcontentDirs := make(map[string]bool)\n\tfor _, p := range pagesBackedByFile {\n\t\tfilename := p.File().Filename()\n\t\tcontentDir := strings.TrimSuffix(filename, p.File().Path())\n\t\tif contentDir == filename {\n\t\t\tcontinue\n\t\t}\n\t\tcontentDirs[filepath.Clean(contentDir)] = true\n\t}\n\n\tvar contentDirList []string\n\tfor contentDir := range contentDirs {","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/commands/convert.go#L181-L217","documentation":"Returned by `hugo convert` when the converted page cannot be written back to disk via `helpers.WriteToDisk` (commands/convert.go:198-199). Parsing and re-encoding succeeded; the failure is purely at the filesystem write step for the computed target filename (in place, or under --output). The doubled colon is a formatting quirk in the source.","triggerScenarios":"Running `hugo convert to*` where the target file or its parent directory is not writable: read-only content files or mounts, insufficient permissions on the --output directory, a full disk, a path component that exists as a file, or on Windows a file locked by another process (editor/sync client).","commonSituations":"Converting inside a Docker container with a read-only bind mount; content files checked out read-only; --output pointing at a protected system path; OneDrive/Dropbox locking files during write; disk-full CI runners.","solutions":["Check permissions on the reported path and its parent directory; ensure the user running hugo can write there (`ls -l`, chown/chmod as needed).","If using --unsafe in-place conversion on a read-only mount, switch to `-o/--output <writable-dir>` instead.","Verify free disk space and that no path component of the target is an existing regular file.","On Windows, close editors/sync clients holding the file and re-run."],"exampleFix":"# before\nhugo convert toYAML --unsafe   # content/ is a read-only mount\n# after\nhugo convert toYAML -o /tmp/converted","handlingStrategy":"try-catch","validationCode":"// Verify the output directory is writable before converting\nf, err := os.CreateTemp(outputDir, \".writecheck*\")\nif err != nil {\n    return fmt.Errorf(\"output dir not writable: %w\", err)\n}\nf.Close()\nos.Remove(f.Name())","typeGuard":null,"tryCatchPattern":"if err != nil {\n    var pathErr *fs.PathError\n    if errors.As(err, &pathErr) {\n        // permission/disk issue: report path and underlying errno, abort before more writes\n    }\n}","preventionTips":["Check disk space and directory permissions before bulk save operations","Use --output to write converted files to a fresh directory instead of overwriting sources","Unwrap with errors.As to *fs.PathError to distinguish permission vs. disk-full causes"],"tags":["hugo","convert","filesystem","permissions"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}