netbirdio/netbird · error
failed to create file
Error message
failed to create file
What it means
HTTP 500 returned when os.OpenFile(filePath, O_WRONLY|O_CREATE|O_EXCL, 0600) fails with an error other than EEXIST, after the upload directory was created successfully. The underlying errno is logged as 'Failed to create file <path>' on the server.
Source
Thrown at upload-server/server/local.go:141
http.Error(w, "invalid path", http.StatusBadRequest)
log.Warnf("Path traversal attempt blocked (file): %s", filePath)
return
}
if err = os.MkdirAll(dirPath, 0750); err != nil {
http.Error(w, "failed to create upload dir", http.StatusInternalServerError)
log.Errorf("Failed to create upload dir: %v", err)
return
}
flags := os.O_WRONLY | os.O_CREATE | os.O_EXCL
f, err := os.OpenFile(filePath, flags, 0600)
if err != nil {
if os.IsExist(err) {
http.Error(w, "file already exists", http.StatusConflict)
return
}
http.Error(w, "failed to create file", http.StatusInternalServerError)
log.Errorf("Failed to create file %s: %v", filePath, err)
return
}
defer func() { _ = f.Close() }()
if _, err = f.Write(body); err != nil {
http.Error(w, "failed to write file", http.StatusInternalServerError)
log.Errorf("Failed to write file %s: %v", filePath, err)
return
}
log.Infof("Uploaded file %s", filePath)
w.WriteHeader(http.StatusOK)
}
View on GitHub (pinned to 93e97f4bf1)
Solutions
- Read the server log line 'Failed to create file <path>: <err>' and fix per errno: permission denied -> ownership/umask; file name too long -> shorten; is a directory -> rename
- Restrict client file names to a safe single segment (letters, digits, '-', '_', '.') before upload
- On SELinux/AppArmor systems, verify the process label may write under STORE_DIR (check audit logs)
Example fix
// before: raw client filename used as segment
name := fileHeader.Filename // "../../x" or 300 chars -> 500
// after: sanitize to one safe segment
name := filepath.Base(fileHeader.Filename)
name = strings.Map(func(r rune) rune {
if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '-' || r == '.' { return r }
return '_'
}, name) Defensive patterns
Strategy: try-catch
Validate before calling
// client-side: keep the file segment short and separator-free
name := filepath.Base(fileName)
if len(name) > 128 || strings.ContainsAny(name, "/\\\x00") {
name = uuid.NewString()
} Try / catch
On 500 'failed to create file', read the server log for the errno (permission denied, name too long, is a directory), fix the environment or the name, then retry once with a fresh URL from GET /upload-url.
Prevention
- Cap client file names to a conservative length (<128 chars) and a safe charset
- Ensure the service user owns every level under STORE_DIR
- On SELinux/AppArmor hosts, allow writes to the state dir label in the policy
When it happens
Trigger: Directory permissions (0750, owner-only) deny create to the process user; the final path component is invalid (contains a decoded '/', a NUL byte, or exceeds NAME_MAX 255); a directory already exists at the exact file path; SELinux/AppArmor denial on the state dir.
Common situations: File names taken straight from client uploads containing separators or extreme length; hardened container security profiles blocking writes outside allowed labels; upload subdirectories created by a different user.
Related errors
- failed to create upload dir
- write private key file (%s): %w
- write public key file (%s): %w
- failed to write file
- failed to list profiles: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/a4e5670a1ea9d03c.
Report an issue: GitHub.