netbirdio/netbird · error
upload failed: %s
Error message
upload failed: %s
What it means
After the daemon assembled the debug bundle, it attempted the upload and reported a failure reason string in the response, which the CLI surfaces here. The bundle file itself was still created locally (its path is printed just above this error). The reason text comes from the daemon's upload attempt: unreachable or invalid upload URL, TLS verification failure against the target, an HTTP error status from the receiving endpoint, or a blocked egress path.
Source
Thrown at client/cmd/debug.go:193
request := &proto.DebugBundleRequest{
Anonymize: anonymizeEnabled,
AnonymizeLevel: anonymizeLevel.String(),
SystemInfo: systemInfoFlag,
LogFileCount: logFileCount,
CliVersion: version.NetbirdVersion(),
}
if uploadBundleFlag {
request.UploadURL = uploadBundleURLFlag
request.UploadInsecure = uploadBundleInsecureFlag
}
resp, err := client.DebugBundle(cmd.Context(), request)
if err != nil {
return daemonCallError("bundle debug", err)
}
cmd.Printf("Local file:\n%s\n", resp.GetPath())
if resp.GetUploadFailureReason() != "" {
return fmt.Errorf("upload failed: %s", resp.GetUploadFailureReason())
}
if uploadBundleFlag {
cmd.Printf("Upload file key:\n%s\n", resp.GetUploadedKey())
}
return nil
}
func setLogLevel(cmd *cobra.Command, args []string) error {
conn, err := getClient(cmd)
if err != nil {
return err
}
defer func() {
if err := conn.Close(); err != nil {
log.Errorf(errCloseConnection, err)
}View on GitHub (pinned to 93e97f4bf1)
Solutions
- Read the printed reason: DNS/connectivity messages mean fix reachability; TLS messages mean fix the certificate or pass --upload-insecure (only for trusted internal endpoints); HTTP status text means inspect the server side
- Verify the URL with curl -v --data-binary @<bundle-path> <url> from the same machine to reproduce independently
- For proxy body-size limits, raise the limit on the receiving server or reduce bundle size (fewer log files via --log-file-count, disable system info)
- The local file path printed before the error still holds the full bundle — share it manually if upload cannot be fixed
Example fix
# before: private-CA upload endpoint, secure verify fails netbird debug bundle --upload --url https://collector.internal/debug # -> upload failed: tls: failed to verify certificate # after: trust the internal endpoint explicitly netbird debug bundle --upload --url https://collector.internal/debug --upload-insecure
Defensive patterns
Strategy: validation
Validate before calling
// Probe the upload endpoint before asking the daemon to upload:
u, err := url.Parse(uploadURL)
if err != nil || (u.Scheme != "https" && u.Scheme != "http") {
return fmt.Errorf("invalid upload URL")
}
if _, err := http.Head(uploadURL); err != nil && !isHTTPOK(err) {
// connectivity/TLS problem: fix before running with --upload
} Type guard
// Distinguish the three failure families from the reason string:
func classifyUploadFailure(reason string) string {
switch {
case strings.Contains(reason, "tls:"):
return "certificate"
case strings.Contains(reason, "connection refused"), strings.Contains(reason, "no such host"):
return "connectivity"
default:
return "server"
}
} Try / catch
// Always keep the local bundle even when upload fails:
if err := runBundle(); err != nil {
if strings.HasPrefix(err.Error(), "upload failed") {
warn(err) // local path was already printed; upload can be retried manually
return nil
}
return err
} Prevention
- curl-test the upload URL from the same host before enabling --upload
- Pass --upload-insecure only for internal endpoints with private CAs, never for public ones
- Shrink bundles (fewer log files) when a size-limited proxy sits in front of the collector
When it happens
Trigger: --upload with a URL that is wrong (typo, wrong scheme, missing endpoint path); the receiving endpoint returns 4xx/5xx (auth required, size limits); self-signed or internal-CA certificate on the upload server without --upload-insecure; device egress blocking the upload host (firewall/proxy); DNS failure for the upload host.
Common situations: Support-tool flows where the URL was transcribed manually; uploads to an internal collector with a private CA while the flag for insecure upload was not passed; large bundles exceeding a reverse-proxy body limit (nginx client_max_body_size); cloud environments with egress allow-lists.
Related errors
- upload debug bundle: %w
- WebSocket connection failed
- failed to create auth client: %v
- get active profile: %v
- get current user: %v
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/0d5681e5d4e43f31.
Report an issue: GitHub.