{"record":{"id":"12527d62d1320f31","repo":"juanfont/headscale","slug":"creating-directory-failed-with-permission-error","errorCode":null,"errorMessage":"creating directory failed with permission error","messagePattern":"creating directory failed with permission error","errorType":"console","errorClass":"util.ErrDirectoryPermission","httpStatus":null,"severity":"error","filePath":"hscontrol/util/file.go","lineNumber":25,"sourceCode":"\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/spf13/viper\"\n)\n\nconst (\n\tBase8              = 8\n\tBase10             = 10\n\tBitSize16          = 16\n\tBitSize32          = 32\n\tBitSize64          = 64\n\tPermissionFallback = 0o700\n)\n\n// ErrDirectoryPermission is returned when creating a directory fails due to permission issues.\nvar ErrDirectoryPermission = errors.New(\"creating directory failed with permission error\")\n\nfunc AbsolutePathFromConfigPath(path string) string {\n\t// If a relative path is provided, prefix it with the directory where\n\t// the config file was found.\n\tif (path != \"\") && !strings.HasPrefix(path, string(os.PathSeparator)) {\n\t\tdir, _ := filepath.Split(viper.ConfigFileUsed())\n\t\tif dir != \"\" {\n\t\t\tpath = filepath.Join(dir, path)\n\t\t}\n\t}\n\n\treturn path\n}\n\nfunc GetFileMode(key string) fs.FileMode {\n\tmodeStr := viper.GetString(key)\n\n\tmode, err := strconv.ParseUint(modeStr, Base8, BitSize64)","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/util/file.go#L7-L43","documentation":"ErrDirectoryPermission (hscontrol/util/file.go:25) is returned from the directory-creation helper at hscontrol/util/file.go:56 when os.MkdirAll fails with a filesystem permission error for a configured directory (the message appends the dir path: \"creating directory failed with permission error: <dir>\"). Headscale creates several runtime directories from config (private key path, ACME/Let's Encrypt cache dir, noise private key dir, etc.) and refuses to continue if it cannot create and write them. The PermissionFallback = 0o700 constant shows dirs are created owner-only.","triggerScenarios":"Starting headscale as a user that lacks write access to a configured path such as tls_letsencrypt_cache_dir, the private key directory, or database directory when that parent does not yet exist; a read-only filesystem or wrong ownership under /var/lib/headscale.","commonSituations":"Running the binary as root once (dirs become root-owned) then switching to the headscale user; systemd unit with an unexpected WorkingDirectory/User; container with a read-only mount at the state path.","solutions":["chown the state/cache directories to the user running headscale: `chown -R headscale:headscale /var/lib/headscale`","Point the failing config key (visible in the error text after the colon) at a writable absolute path","If running in a container, ensure the volume is mounted writable"],"exampleFix":"# before\ntls_letsencrypt_cache_dir: /etc/letsencrypt-cache   # not writable by headscale user\n\n# after\ntls_letsencrypt_cache_dir: /var/lib/headscale/acme\n# and: chown -R headscale:headscale /var/lib/headscale","handlingStrategy":"validation","validationCode":"// pre-flight: every configured dir must be creatable+writable\nfor _, dir := range []string{cfg.TLS.LetsEncrypt.CacheDir, stateDir} {\n\tif dir == \"\" {\n\t\tcontinue\n\t}\n\tif err := unix.Access(filepath.Dir(dir), unix.W_OK); err != nil {\n\t\treturn fmt.Errorf(\"no write access for %s: %w\", dir, err)\n\t}\n}","typeGuard":null,"tryCatchPattern":"if err := util.EnsureDirWritable(dir); err != nil {\n\tif errors.Is(err, util.ErrDirectoryPermission) {\n\t\t// message already carries the dir path; chown it or change the config key\n\t\tlog.Fatalf(\"fix permissions on the directory named in: %v\", err)\n\t}\n}","preventionTips":["chown state/cache dirs to the service user as part of deployment","Run the server as one dedicated user consistently — never mix root and service user","Check writable mounts in containers before first boot"],"tags":["filesystem","permissions","startup","config"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}