{"record":{"id":"9c6e6c417dcd7b95","repo":"henrygd/beszel","slug":"failed-to-create-update-directory-w","errorCode":null,"errorMessage":"failed to create update directory: %w","messagePattern":"failed to create update directory: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/ghupdate/ghupdate.go","lineNumber":147,"sourceCode":"\tnewVersion := semver.MustParse(strings.TrimPrefix(latest.Tag, \"v\"))\n\n\tif newVersion.LTE(currentVersion) {\n\t\tColorPrintf(ColorGreen, \"You already have the latest version %s.\", p.currentVersion)\n\t\treturn false, nil\n\t}\n\n\tsuffix := archiveSuffix(p.config.ArchiveExecutable, runtime.GOOS, runtime.GOARCH, buildGOARM)\n\tasset, err := latest.findAssetBySuffix(suffix)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif err := os.MkdirAll(p.config.DataDir, 0755); err != nil {\n\t\treturn false, fmt.Errorf(\"failed to create update data directory: %w\", err)\n\t}\n\treleaseDir, err := os.MkdirTemp(p.config.DataDir, \".beszel_update-\")\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"failed to create update directory: %w\", err)\n\t}\n\tdefer os.RemoveAll(releaseDir)\n\n\tColorPrintf(ColorYellow, \"Downloading %s...\", asset.Name)\n\n\t// download the release asset\n\tassetPath, err := archivePath(releaseDir, asset.Name)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tif err := downloadFile(p.config.Context, p.config.HttpClient, asset.DownloadUrl, assetPath, p.config.UseMirror); err != nil {\n\t\treturn false, err\n\t}\n\tColorPrint(ColorYellow, \"Verifying checksum...\")\n\tif err := verifyAssetChecksum(assetPath, asset.Digest); err != nil {\n\t\treturn false, err\n\t}\n","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/henrygd/beszel/blob/b38fb7dafa60812cc22e6a84ce313e94f1ce0a32/internal/ghupdate/ghupdate.go#L129-L165","documentation":"After ensuring DataDir exists, update() creates a unique temporary staging directory inside it with os.MkdirTemp. Failure here (wrapped with this message) usually means DataDir exists but is not writable by the current user, or a race/permission quirk prevents creating new entries in it.","triggerScenarios":"ghupdate.Update -> update when os.MkdirTemp(DataDir, \".beszel_update-\") fails: DataDir has 0755 owned by another user, noexec/no-write mount options, disk full (inode or space exhaustion), or a security module blocking temp dir creation.","commonSituations":"DataDir writable only by root while the updater runs unprivileged; container with read-only rootfs and DataDir defaulting to os.TempDir(); tmpfs full; paranoid umask or hardened systemd service settings (ProtectSystem=strict without ReadWritePaths).","solutions":["Grant the running user write access to DataDir: `sudo chown -R <user> <DataDir>` or adjust mode to 0770/0775 with group ownership.","Set Config.DataDir to a directory the service user owns and can write to.","Check disk space and inodes: `df -h <DataDir> && df -i <DataDir>`.","If running under systemd hardening, add DataDir to ReadWritePaths= in the unit file."],"exampleFix":"// before (systemd unit)\n[Service]\nProtectSystem=strict\n// after\n[Service]\nProtectSystem=strict\nReadWritePaths=/var/lib/beszel","handlingStrategy":"validation","validationCode":"probe, err := os.CreateTemp(cfg.DataDir, \".write-probe-*\")\nif err != nil {\n    return fmt.Errorf(\"DataDir %q is not writable: %w\", cfg.DataDir, err)\n}\nprobe.Close()\nos.Remove(probe.Name())","typeGuard":null,"tryCatchPattern":"updated, err := ghupdate.Update(cfg)\nif err != nil && strings.Contains(err.Error(), \"failed to create update directory\") {\n    log.Printf(\"cannot create staging dir in DataDir (%v); check write permission, disk space, and systemd ReadWritePaths\", err)\n}","preventionTips":["Ensure the service user can create files in DataDir (test with `touch <DataDir>/.probe`).","Under systemd hardening (ProtectSystem=strict), add DataDir to ReadWritePaths=.","Monitor free space and inodes on the DataDir filesystem.","Keep DataDir off read-only or noexec-constrained mounts."],"tags":["filesystem","permissions","tempdir","self-update"],"backgroundTag":"permission-denied","analyzedSha":"b38fb7dafa60812cc22e6a84ce313e94f1ce0a32","analyzedAt":"2026-08-31T15:10:10.149Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}