sipeed/picoclaw · warning

invalid trusted proxy CIDR %q

Error message

invalid trusted proxy CIDR %q

What it means

Validation error (400) from PUT /api/system/launcher-config: a trusted_proxy_cidrs entry failed net.ParseCIDR (launcherconfig/config.go:60-64). Same format rules as allowed_cidrs: full CIDR with prefix required. trusted_proxy_cidrs governs which proxies are trusted for X-Forwarded-For handling, so a typical mistake is entering the proxy's hostname or a bare IP instead of its network in CIDR form.

Source

Thrown at web/backend/api/launcher_config.go:92

		http.Error(w, fmt.Sprintf("Invalid JSON: %v", err), http.StatusBadRequest)
		return
	}

	cfg, err := h.loadLauncherConfig()
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to load launcher config: %v", err), http.StatusInternalServerError)
		return
	}
	cfg.Port = payload.Port
	cfg.Public = payload.Public
	cfg.AllowedCIDRs = append([]string(nil), payload.AllowedCIDRs...)
	if payload.AllowLocalhostBypass != nil {
		cfg.AllowLocalhostBypass = *payload.AllowLocalhostBypass
	}
	cfg.TrustedProxyCIDRs = append([]string(nil), payload.TrustedProxyCIDRs...)
	cfg.LegacyLauncherToken = ""
	if err := launcherconfig.Validate(cfg); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	if err := launcherconfig.Save(h.launcherConfigPath(), cfg); err != nil {
		http.Error(w, fmt.Sprintf("Failed to save launcher config: %v", err), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(launcherConfigPayload{
		Port:                 cfg.Port,
		Public:               cfg.Public,
		AllowedCIDRs:         append([]string(nil), cfg.AllowedCIDRs...),
		AllowLocalhostBypass: cfg.AllowLocalhostBypass,
		TrustedProxyCIDRs:    append([]string(nil), cfg.TrustedProxyCIDRs...),
	})
}

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Express each trusted proxy as CIDR: "10.1.2.3/32" for one host, "10.0.0.0/8" for a range
  2. Resolve hostnames to addresses first - the validator only accepts numeric CIDRs
  3. Trim entries client-side; the error message quotes the exact bad value

Example fix

// before
{"trusted_proxy_cidrs": ["proxy.internal.lan"]}

// after - resolved address as /32
{"trusted_proxy_cidrs": ["10.1.2.3/32"]}
Defensive patterns

Strategy: validation

Validate before calling

// Reuse the same CIDR check as allowed_cidrs before sending.
const badProxies = payload.trusted_proxy_cidrs.filter(c => !isValidCIDR(c));
if (badProxies.length) {
  // common case: user typed the proxy hostname - resolve it first
  throw new Error('trusted proxies must be CIDRs (e.g. 10.1.2.3/32), got: ' + badProxies.join(', '));
}

Type guard

const isTrustedProxyList = (v: unknown): v is string[] =>
  Array.isArray(v) && v.every(x => typeof x === 'string' && isValidCIDR(x));

Try / catch

if (res.status === 400) {
  const text = await res.text();
  const m = text.match(/invalid trusted proxy CIDR "(.*)"/);
  if (m) highlightField('trusted_proxy_cidrs', m[1]);
  throw new Error(text);
}

Prevention

When it happens

Trigger: Sending "proxy.internal.lan" (hostname) or "10.1.2.3" (bare IP) instead of "10.1.2.3/32"; IPv6 without a prefix; whitespace-contaminated entries validated before Save's NormalizeCIDRs runs.

Common situations: Configuring reverse-proxy trust for the first time and copying the proxy address straight from DNS; load balancer docs that list IPs without prefixes.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/578c2864a4194fbb. Report an issue: GitHub.