netbirdio/netbird · warning

client not found

Error message

client not found

What it means

The packet-capture debug endpoint GET /debug/clients/{accountID}/capture resolves the account through provider.GetClient before touching any query parameter. If the proxy process holds no client for that account ID, the request fails with 404 before duration, filter, or format are considered.

Source

Thrown at proxy/internal/debug/handler.go:824

		// Values are reported in kB.
		out[k] = n * 1024
	}
	return out
}

const maxCaptureDuration = 30 * time.Minute

// handleCapture streams a pcap or text packet capture for the given client.
//
// Query params:
//
//	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)
		}
	}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Re-list clients via GET /debug/clients and use a live account_id
  2. Verify you reached the same proxy instance that owns the account
  3. Check /debug/health and proxy logs if you expect the client to be running
Defensive patterns

Strategy: validation

Validate before calling

ids, err := fetchAccountIDs(proxyBase) // GET /debug/clients?format=json
if err != nil {
    return err
}
if !slices.Contains(ids, accountID) {
    return fmt.Errorf("cannot capture: account %s unknown on this proxy", accountID)
}

Type guard

func isCaptureableAccount(liveIDs []string, id string) bool {
    return slices.Contains(liveIDs, id)
}

Prevention

When it happens

Trigger: GET /debug/clients/<id>/capture?... where <id> is unknown to this proxy process: stale, mistyped, or a client that was never started on this instance.

Common situations: Deep link from a debug page captured during a previous proxy run; capturing against a proxy replica that does not own the account; the account was removed while the page stayed open.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/26d7f0cc777fe9b1. Report an issue: GitHub.