{"record":{"id":"2e600a02c64672b9","repo":"yorukot/superfile","slug":"error-saving-pinned-directories-w","errorCode":null,"errorMessage":"error saving pinned directories: %w","messagePattern":"error saving pinned directories: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/internal/ui/sidebar/pinned.go","lineNumber":84,"sourceCode":"\tunPinned := false\n\n\tfor i, other := range dirs {\n\t\tif other.Location == dir {\n\t\t\tdirs = append(dirs[:i], dirs[i+1:]...)\n\t\t\tunPinned = true\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif !unPinned {\n\t\tdirs = append(dirs, directory{\n\t\t\tLocation: dir,\n\t\t\tName:     filepath.Base(dir),\n\t\t})\n\t}\n\n\tif err := mgr.Save(dirs); err != nil {\n\t\treturn fmt.Errorf(\"error saving pinned directories: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Clean removes non-existing directories and optionally saves the updated list\nfunc (mgr *PinnedManager) Clean(dirs []directory) []directory {\n\tcleanedDirs := make([]directory, 0, len(dirs))\n\tfor _, dir := range dirs {\n\t\tif _, err := os.Stat(dir.Location); err == nil {\n\t\t\tcleanedDirs = append(cleanedDirs, dir)\n\t\t} else if !os.IsNotExist(err) {\n\t\t\tslog.Warn(\"error while checking pinned directory\", \"directory\", dir.Location, \"error\", err)\n\t\t}\n\t}\n\n\tif len(cleanedDirs) == len(dirs) {\n\t\treturn cleanedDirs","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/yorukot/superfile/blob/b72f550bc6e75913f48eb49fdd258e1a2df2fe88/src/internal/ui/sidebar/pinned.go#L66-L102","documentation":"Toggle adds or removes a directory in the pinned list and then persists the list via mgr.Save. This error wraps any error returned by Save (JSON marshal or file write failure), attributing it to the save step of toggling. The in-memory toggle itself has already happened, so the error indicates the change was not persisted.","triggerScenarios":"Calling Toggle with any directory when the underlying Save fails: unwritable config file, missing parent directory, marshal failure, or disk full.","commonSituations":"Users pinning a directory in an environment where the config directory was deleted mid-session, or where the pinned.json file is owned by another user or made read-only.","solutions":["Ensure the config directory exists and is writable before calling Toggle","Check pinned.json permissions (read-only file causes write failure)","Inspect the wrapped error chain for the root OS cause","Re-create the config directory if it was removed"],"exampleFix":"// before\nif err := mgr.Toggle(dir); err != nil {\n\treturn err\n}\n// after\nif err := os.MkdirAll(filepath.Dir(mgr.FilePath()), 0o755); err != nil {\n\treturn fmt.Errorf(\"cannot prepare config dir: %w\", err)\n}\nif err := mgr.Toggle(dir); err != nil {\n\treturn err\n}","handlingStrategy":"try-catch","validationCode":"if _, err := os.Stat(filepath.Dir(mgr.filePath)); os.IsNotExist(err) {\n\tos.MkdirAll(filepath.Dir(mgr.filePath), 0o755)\n}","typeGuard":null,"tryCatchPattern":"if err := mgr.Toggle(dir); err != nil {\n\tvar wrapped interface{ Unwrap() error }\n\tif errors.As(err, &errors.Wrapper{}) || err.Error() != \"\" {\n\t\tlog.Printf(\"toggle not persisted: %v\", err)\n\t}\n}","preventionTips":["Ensure config dir exists before UI interactions that call Toggle","Verify file permissions after packaging/installing the app","Handle the error in the UI so users know the pin was not saved","Test toggle behavior with a read-only HOME in CI"],"tags":["go","filesystem","persistence","sidebar"],"backgroundTag":"file-write-failed","analyzedSha":"b72f550bc6e75913f48eb49fdd258e1a2df2fe88","analyzedAt":"2026-09-01T04:38:08.254Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}