netbirdio/netbird · warning
duration must not be negative
Error message
duration must not be negative
What it means
A duration that parses successfully but is negative is rejected explicitly: the handler checks d < 0 after time.ParseDuration. Zero is allowed and means 'use the 30-minute maximum'; only values below zero are refused.
Source
Thrown at proxy/internal/debug/handler.go:836
// duration: capture duration (0 or absent = max, capped at 30m)
// format: "text" for human-readable output (default: pcap)
// filter: BPF-like filter expression (e.g. "host 10.0.0.1 and tcp port 443")
func (h *Handler) handleCapture(w http.ResponseWriter, r *http.Request, accountID types.AccountID) {
client, ok := h.provider.GetClient(accountID)
if !ok {
http.Error(w, "client not found", http.StatusNotFound)
return
}
duration := maxCaptureDuration
if durationStr := r.URL.Query().Get("duration"); durationStr != "" {
d, err := time.ParseDuration(durationStr)
if err != nil {
http.Error(w, "invalid duration: "+err.Error(), http.StatusBadRequest)
return
}
if d < 0 {
http.Error(w, "duration must not be negative", http.StatusBadRequest)
return
}
if d > 0 {
duration = min(d, maxCaptureDuration)
}
}
filter := r.URL.Query().Get("filter")
wantText := r.URL.Query().Get("format") == "text"
verbose := r.URL.Query().Get("verbose") == "true"
ascii := r.URL.Query().Get("ascii") == "true"
opts := nbembed.CaptureOptions{Filter: filter, Verbose: verbose, ASCII: ascii}
if wantText {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
opts.TextOutput = w
} else {
w.Header().Set("Content-Type", "application/vnd.tcpdump.pcap")View on GitHub (pinned to 93e97f4bf1)
Solutions
- Send a positive duration or omit the parameter
- Clamp computed durations to zero before sending: if d < 0 { d = 0 }
- Treat a negative remaining time in the caller as 'capture window already ended' and skip the request
Example fix
// before
d := deadline.Sub(time.Now()) // may be negative once the deadline passed
GET /debug/clients/<id>/capture?duration=<d>
// after
if d < 0 {
d = 0 // zero means 'use the 30m maximum'
} Defensive patterns
Strategy: validation
Validate before calling
d, err := time.ParseDuration(s)
if err != nil {
return err
}
if d < 0 {
d = 0 // zero selects the 30-minute maximum
}
q := url.Values{"duration": []string{d.String()}} Type guard
func isNonNegativeDuration(s string) bool {
d, err := time.ParseDuration(s)
return err == nil && d >= 0
} Prevention
- Clamp deadline-derived durations to zero before building the URL
- Treat a negative remaining window in the caller as 'already finished' and skip the request
When it happens
Trigger: GET /debug/clients/<id>/capture?duration=-1s or any negative Go duration string, e.g. a computed 'time until deadline' that already passed.
Common situations: Computing duration as deadline minus now, which goes negative once the deadline passes; a UI numeric field with a minus sign; sign errors in generated URLs.
Related errors
- invalid duration: {}
- value parameter is required
- invalid value %q: %v
- client not found
- host argument required
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/df6a7713e7ae501b.
Report an issue: GitHub.