{"record":{"id":"2fd4410762da627e","repo":"juanfont/headscale","slug":"creating-directory-s-w","errorCode":null,"errorMessage":"creating directory %s: %w","messagePattern":"creating directory (.+?): %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/util/file.go","lineNumber":59,"sourceCode":"\tmodeStr := viper.GetString(key)\n\n\tmode, err := strconv.ParseUint(modeStr, Base8, BitSize64)\n\tif err != nil {\n\t\treturn PermissionFallback\n\t}\n\n\treturn fs.FileMode(mode) //nolint:gosec // file mode is bounded by ParseUint\n}\n\nfunc EnsureDir(dir string) error {\n\tif _, err := os.Stat(dir); os.IsNotExist(err) { //nolint:noinlineerr\n\t\terr := os.MkdirAll(dir, PermissionFallback)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, os.ErrPermission) {\n\t\t\t\treturn fmt.Errorf(\"%w: %s\", ErrDirectoryPermission, dir)\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"creating directory %s: %w\", dir, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":41,"sourceCodeEnd":65,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/util/file.go#L41-L65","documentation":"Returned by util.EnsureDir when os.MkdirAll fails for any reason other than a permission error (wrapped with the directory path and the raw error). Typical causes include a path component being a regular file, I/O errors, or invalid path syntax.","triggerScenarios":"Calling EnsureDir where some component of dir already exists as a file (e.g. /var/lib/headscale is a file), extremely long paths, or ENOSPC/EROFS device errors during MkdirAll.","commonSituations":"A config pointing tls_cert_path or state storage under a path that collides with an existing file; disk-full conditions in containers; leftover artifacts from previous installations.","solutions":["Check whether any component of the path already exists as a file and remove or relocate it","Free disk space or remount the volume read-write if the error is EROFS/ENOSPC","Inspect the wrapped error text for the syscall reason (ENOTDIR, ENOSPC, EROFS) and fix the underlying filesystem state"],"exampleFix":"# before\n# /etc/headscale/certs is a regular file left by an old install\n# after\nsudo rm /etc/headscale/certs && sudo mkdir -p /etc/headscale/certs","handlingStrategy":"try-catch","validationCode":"if fi, err := os.Stat(dir); err == nil && !fi.IsDir() {\n    return fmt.Errorf(\"path %s exists and is not a directory\", dir)\n}","typeGuard":null,"tryCatchPattern":"if err := util.EnsureDir(dir); err != nil {\n    if errors.Is(err, util.ErrDirectoryPermission) {\n        // ownership fix path\n    }\n    // inspect wrapped syscall error: ENOTDIR => collision with a file, ENOSPC => disk\n    return err\n}","preventionTips":["Avoid path collisions between files and directories in config layouts","Check disk space in container healthchecks before it becomes ENOSPC","Clean old install artifacts before redeploying to the same paths"],"tags":["filesystem","startup","io"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}