fatedier/frp · warning

invalid limiter burst: %d

Error message

invalid limiter burst: %d

What it means

invalidBurstError was meant to flag a bandwidth limiter burst value that does not fit in an int (needed because x/time/rate takes burst as int while bandwidth is int64). In the current code it is unused dead code: NewBandwidthLimiter clamps the burst with min(bytes, maxInt) and returns a valid limiter for any positive bytes, returning nil for bytes <= 0. No runtime path can emit this error in this version.

Source

Thrown at pkg/util/limit/limiter.go:36

	"fmt"

	"golang.org/x/time/rate"
)

// NewBandwidthLimiter creates a limiter whose rate preserves the configured
// byte limit while keeping the burst representable as an int on all targets.
func NewBandwidthLimiter(bytes int64) *rate.Limiter {
	if bytes <= 0 {
		return nil
	}

	maxInt := int64(^uint(0) >> 1)
	burst := min(bytes, maxInt)
	return rate.NewLimiter(rate.Limit(float64(bytes)), int(burst))
}

func invalidBurstError(burst int) error {
	return fmt.Errorf("invalid limiter burst: %d", burst)
}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Current versions: nothing to fix — the value is clamped; no error can occur.
  2. Forks: replace validation with clamping as upstream does (burst := min(bytes, maxInt)).
  3. Callers should treat a nil return from NewBandwidthLimiter as 'no limiting', which is how bytes <= 0 is handled.

Example fix

// fork pattern — before
burst := int(bytes)
if int64(burst) != bytes {
    return nil, invalidBurstError(burst) // can panic/fire on 32-bit
}

// after (upstream behavior)
maxInt := int64(^uint(0) >> 1)
burst := min(bytes, maxInt)
return rate.NewLimiter(rate.Limit(float64(bytes)), int(burst))
Defensive patterns

Strategy: validation

Validate before calling

// callers: NewBandwidthLimiter returns nil when no limit applies — guard it
limiter := limit.NewBandwidthLimiter(cfg.BandwidthLimit)
if limiter == nil {
    // bandwidth limit unset or <= 0: skip wrapping the conn
    return rawConn, nil
}

Prevention

When it happens

Trigger: None in the shipped code — the function is never called. It would only fire in older or forked versions that validated burst before clamping, when the configured bytes-per-second exceeded math.MaxInt on 32-bit platforms.

Common situations: Grepping the codebase; using a fork that still calls invalidBurstError; seeing it referenced in old issues about bandwidth limits on 32-bit builds.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/f1381eb9677a394c. Report an issue: GitHub.