fatedier/frp · error

invalid effective pool count %d, cannot safely add %d for wo

Error message

invalid effective pool count %d, cannot safely add %d for work connection pool capacity

What it means

NewControl computes effectivePoolCount = min(client PoolCount, server MaxPoolCount) and checks it against math.MaxInt - workConnPoolCapacityOffset so that poolCount + offset cannot overflow int when sizing the workConnCh channel. An absurdly large value (near MaxInt) fails here instead of panicking on channel creation.

Source

Thrown at server/control.go:449

	ctx           context.Context
	doneCh        chan struct{}
	serverMetrics metrics.ServerMetrics
}

func NewControl(ctx context.Context, sessionCtx *SessionContext) (*Control, error) {
	if sessionCtx.LoginMsg.PoolCount < 0 {
		return nil, fmt.Errorf("invalid pool count %d, must be non-negative", sessionCtx.LoginMsg.PoolCount)
	}
	if sessionCtx.ServerCfg.Transport.MaxPoolCount < 0 {
		return nil, fmt.Errorf(
			"invalid max pool count %d, must be non-negative",
			sessionCtx.ServerCfg.Transport.MaxPoolCount,
		)
	}
	effectivePoolCount := min(int64(sessionCtx.LoginMsg.PoolCount), sessionCtx.ServerCfg.Transport.MaxPoolCount)
	maxPoolCountForChannel := int64(math.MaxInt) - int64(workConnPoolCapacityOffset)
	if effectivePoolCount > maxPoolCountForChannel {
		return nil, fmt.Errorf(
			"invalid effective pool count %d, cannot safely add %d for work connection pool capacity",
			effectivePoolCount, workConnPoolCapacityOffset,
		)
	}
	poolCount := int(effectivePoolCount)
	ctl := &Control{
		sessionCtx:    sessionCtx,
		workConnCh:    make(chan *proxy.WorkConn, poolCount+workConnPoolCapacityOffset),
		proxies:       make(map[string]proxy.Proxy),
		poolCount:     poolCount,
		portsUsedNum:  0,
		runID:         sessionCtx.LoginMsg.RunID,
		state:         controlStateCreated,
		xl:            xlog.FromContextSafe(ctx),
		ctx:           ctx,
		doneCh:        make(chan struct{}),
		serverMetrics: metrics.Server,
	}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Cap pool counts to realistic values in config (single digits to low hundreds).
  2. If you run a public frps, validate/limit login fields at the trust boundary before control creation.
  3. Reject the client session — this value cannot be honoured, so retrying with the same number is futile.

Example fix

# frps.toml — hard ceiling for any client
[transport]
maxPoolCount = 100
Defensive patterns

Strategy: validation

Validate before calling

const sanePoolMax = 1024
if loginMsg.PoolCount > sanePoolMax || cfg.Transport.MaxPoolCount > sanePoolMax {
    return fmt.Errorf("pool count unrealistically large")
}

Prevention

When it happens

Trigger: A client (or misconfigured server max) supplies a pool count within a few units of 2^63-1 on 64-bit. make(chan ..., huge) would try to allocate an impossible buffer, so the guard rejects it first.

Common situations: Malicious or fuzzed login frames with extreme integers; config values accidentally set to huge numbers (e.g. pasting a bit pattern); custom clients reusing an uninitialised int that happens to be large.

Related errors


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