{"record":{"id":"b17544f35169d57e","repo":"kovidgoyal/kitty","slug":"could-not-find-any-writable-data-directories-make","errorCode":null,"errorMessage":"Could not find any writable data directories. Make sure XDG_DATA_DIRS is set and contains at least one directory for which you have write permission","messagePattern":"Could not find any writable data directories\\. Make sure XDG_DATA_DIRS is set and contains at least one directory for which you have write permission","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kittens/desktop_ui/portal.go","lineNumber":393,"sourceCode":"\t\t\t\tlines = append(lines, line)\n\t\t\t}\n\t\t}\n\t}\n\n\tif !patched {\n\t\t// the file was empty or did not contain a section\n\t\tlines = append(lines, \"[preferred]\")\n\t\tfor _, iface := range AllPortalInterfaces() {\n\t\t\tlines = append(lines, iface+\"=kitty;*\")\n\t\t}\n\t}\n\n\treturn utils.UnsafeStringToBytes(strings.Join(lines, \"\\n\"))\n}\n\nfunc enable_portal() (err error) {\n\tif len(WritableDataDirs()) == 0 {\n\t\treturn fmt.Errorf(\"Could not find any writable data directories. Make sure XDG_DATA_DIRS is set and contains at least one directory for which you have write permission\")\n\t}\n\tportals_dir := \"\"\n\tfor _, x := range WritableDataDirs() {\n\t\t// Find-or-create the first available xdg-desktop-portals/portals directory\n\t\tq := filepath.Join(x, \"xdg-desktop-portal\", \"portals\")\n\t\tif (unix.Access(q, unix.W_OK) == nil && IsDir(q)) || (os.MkdirAll(q, 0o755) == nil) {\n\t\t\tportals_dir = q\n\t\t\tbreak\n\t\t}\n\t}\n\tif portals_dir == \"\" {\n\t\treturn fmt.Errorf(\"Could not find any writable portals directories. Make sure XDG_DATA_HOME is set and point to a directory for which you have write permission.\")\n\t}\n\tportals_defn := filepath.Join(portals_dir, \"kitty.portal\")\n\tif err = os.WriteFile(portals_defn, utils.UnsafeStringToBytes(fmt.Sprintf(\n\t\t`[portal]\nDBusName=%s\nInterfaces=%s;","sourceCodeStart":375,"sourceCodeEnd":411,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kittens/desktop_ui/portal.go#L375-L411","documentation":"enable_portal first checks WritableDataDirs(); if none of the XDG data directories is writable it aborts before writing anything. XDG_DATA_HOME and XDG_DATA_DIRS must yield at least one directory writable by the current user.","triggerScenarios":"Running `kitten desktop-ui enable` with XDG_DATA_HOME/XDG_DATA_DIRS unset in a read-only or root-owned hierarchy, or as a user without write permission on those paths.","commonSituations":"Containers with read-only /usr/share; HOME unset so XDG_DATA_HOME resolves to /.local/share in an unwritable location; running as an unprivileged user against root-owned data dirs.","solutions":["Set XDG_DATA_HOME to a writable path, e.g. export XDG_DATA_HOME=$HOME/.local/share","Ensure the directory exists and you have write permission (mkdir -p && touch test)","In containers, mount a writable volume at the data dir"],"exampleFix":"# before\nunset XDG_DATA_HOME; kitten desktop-ui enable\n# after\nexport XDG_DATA_HOME=\"$HOME/.local/share\"; kitten desktop-ui enable","handlingStrategy":"validation","validationCode":"home, _ := os.UserHomeDir()\ndir := os.Getenv(\"XDG_DATA_HOME\")\nif dir == \"\" { dir = filepath.Join(home, \".local\", \"share\") }\nif err := os.MkdirAll(dir, 0o755); err != nil || unix.Access(dir, unix.W_OK) != nil {\n    return errors.New(\"no writable XDG data dir\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set XDG_DATA_HOME explicitly in scripts","Verify writability with a touch test before enabling the portal"],"tags":["xdg","desktop-ui","kitty","filesystem","permissions"],"backgroundTag":"xdg-data-dir-not-writable","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}