{"record":{"id":"455c9f78a8f0fbac","repo":"netbirdio/netbird","slug":"failed-to-create-upload-dir","errorCode":null,"errorMessage":"failed to create upload dir","messagePattern":"failed to create upload dir","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"upload-server/server/local.go","lineNumber":129,"sourceCode":"\n\tcleanBase := filepath.Clean(l.dir) + string(filepath.Separator)\n\n\tdirPath := filepath.Clean(filepath.Join(l.dir, uploadDir))\n\tif !strings.HasPrefix(dirPath, cleanBase) {\n\t\thttp.Error(w, \"invalid path\", http.StatusBadRequest)\n\t\tlog.Warnf(\"Path traversal attempt blocked (dir): %s\", dirPath)\n\t\treturn\n\t}\n\n\tfilePath := filepath.Clean(filepath.Join(dirPath, uploadFile))\n\tif !strings.HasPrefix(filePath, cleanBase) {\n\t\thttp.Error(w, \"invalid path\", http.StatusBadRequest)\n\t\tlog.Warnf(\"Path traversal attempt blocked (file): %s\", filePath)\n\t\treturn\n\t}\n\n\tif err = os.MkdirAll(dirPath, 0750); err != nil {\n\t\thttp.Error(w, \"failed to create upload dir\", http.StatusInternalServerError)\n\t\tlog.Errorf(\"Failed to create upload dir: %v\", err)\n\t\treturn\n\t}\n\n\tflags := os.O_WRONLY | os.O_CREATE | os.O_EXCL\n\tf, err := os.OpenFile(filePath, flags, 0600)\n\tif err != nil {\n\t\tif os.IsExist(err) {\n\t\t\thttp.Error(w, \"file already exists\", http.StatusConflict)\n\t\t\treturn\n\t\t}\n\t\thttp.Error(w, \"failed to create file\", http.StatusInternalServerError)\n\t\tlog.Errorf(\"Failed to create file %s: %v\", filePath, err)\n\t\treturn\n\t}\n\tdefer func() { _ = f.Close() }()\n\n\tif _, err = f.Write(body); err != nil {","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/upload-server/server/local.go#L111-L147","documentation":"HTTP 500 from handlePutRequest when os.MkdirAll(dirPath, 0750) fails while creating the per-id upload directory under the base (STORE_DIR, default /var/lib/netbird). The directory must exist before the file is opened, so any filesystem-level failure at this step aborts the upload; the errno is logged as 'Failed to create upload dir'.","triggerScenarios":"Server process runs as a user without write permission on the base dir (a root-owned /var/lib/netbird); STORE_DIR on a read-only volume; a component of STORE_DIR exists as a regular file; disk or inode exhaustion.","commonSituations":"Running the upload-server container without a writable state volume; deploying as a non-root systemd service without chowning the state dir; Kubernetes pods with readOnlyRootFilesystem and no writable emptyDir mounted at STORE_DIR.","solutions":["Pre-create the base dir owned by the service user: mkdir -p /var/lib/netbird && chown <svcuser> /var/lib/netbird, or point STORE_DIR at a writable absolute path","If the container filesystem is read-only, mount a writable volume at STORE_DIR","Verify no regular file occupies any prefix of the path and check df -h / df -i for space or inode exhaustion"],"exampleFix":"# before: read-only container fs, every PUT returns 500 'failed to create upload dir'\ndocker run -e STORE_DIR=/var/lib/netbird nb/upload-server\n\n# after: writable state dir mounted and owned\ndocker run -e STORE_DIR=/var/lib/netbird -v nbuploads:/var/lib/netbird nb/upload-server","handlingStrategy":"validation","validationCode":"// fail fast at startup instead of 500 on every upload\ninfo, err := os.Stat(storeDir)\nif err != nil || !info.IsDir() {\n\tlog.Fatalf(\"STORE_DIR unusable: %v\", err)\n}\nprobe := filepath.Join(storeDir, \".writable-probe\")\nif f, err := os.OpenFile(probe, os.O_WRONLY|os.O_CREATE, 0600); err != nil {\n\tlog.Fatalf(\"STORE_DIR not writable: %v\", err)\n} else {\n\t_ = f.Close()\n\t_ = os.Remove(probe)\n}","typeGuard":null,"tryCatchPattern":"A 500 'failed to create upload dir' is a server-side environment fault; surface it to the operator (it will not self-heal on retry) and stop the upload batch.","preventionTips":["Pre-create STORE_DIR and chown it to the service user before launch","Mount a writable volume at STORE_DIR in read-only-rootfs containers","Add a writability probe to the health/readiness check"],"tags":["filesystem","permissions","upload","go","deployment"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}