{"record":{"id":"468adb6a1a79d363","repo":"fatedier/frp","slug":"invalid-max-pool-count-d-must-be-non-negative","errorCode":null,"errorMessage":"invalid max pool count %d, must be non-negative","messagePattern":"invalid max pool count (.+?), must be non-negative","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/control.go","lineNumber":441,"sourceCode":"\thandoffBarrier <-chan struct{}\n\n\tinterruptOnce sync.Once\n\tinterruptErr  error\n\n\tmu sync.RWMutex\n\n\txl            *xlog.Logger\n\tctx           context.Context\n\tdoneCh        chan struct{}\n\tserverMetrics metrics.ServerMetrics\n}\n\nfunc NewControl(ctx context.Context, sessionCtx *SessionContext) (*Control, error) {\n\tif sessionCtx.LoginMsg.PoolCount < 0 {\n\t\treturn nil, fmt.Errorf(\"invalid pool count %d, must be non-negative\", sessionCtx.LoginMsg.PoolCount)\n\t}\n\tif sessionCtx.ServerCfg.Transport.MaxPoolCount < 0 {\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"invalid max pool count %d, must be non-negative\",\n\t\t\tsessionCtx.ServerCfg.Transport.MaxPoolCount,\n\t\t)\n\t}\n\teffectivePoolCount := min(int64(sessionCtx.LoginMsg.PoolCount), sessionCtx.ServerCfg.Transport.MaxPoolCount)\n\tmaxPoolCountForChannel := int64(math.MaxInt) - int64(workConnPoolCapacityOffset)\n\tif effectivePoolCount > maxPoolCountForChannel {\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"invalid effective pool count %d, cannot safely add %d for work connection pool capacity\",\n\t\t\teffectivePoolCount, workConnPoolCapacityOffset,\n\t\t)\n\t}\n\tpoolCount := int(effectivePoolCount)\n\tctl := &Control{\n\t\tsessionCtx:    sessionCtx,\n\t\tworkConnCh:    make(chan *proxy.WorkConn, poolCount+workConnPoolCapacityOffset),\n\t\tproxies:       make(map[string]proxy.Proxy),\n\t\tpoolCount:     poolCount,","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/server/control.go#L423-L459","documentation":"NewControl also validates the server-side config: ServerCfg.Transport.MaxPoolCount must be non-negative. This is an operator configuration error on frps, independent of any client input; the control (and thus the client session) is rejected at construction.","triggerScenarios":"frps is started with transport.maxPoolCount set to a negative number in its config file. The first client login that constructs a Control hits this check and every subsequent login fails too.","commonSituations":"Typo or env-var interpolation mistake in frps.toml producing a negative value (e.g. empty var parsed as -1 by a template layer); copying a config snippet with a placeholder; manual edits after an upgrade.","solutions":["Fix frps.toml: set transport.maxPoolCount to a positive value (default 5) or remove it to use the default.","Validate config before deploy: run `frps verify -c frps.toml` or your config linter in CI.","Restart frps after correcting the value."],"exampleFix":"# frps.toml — before\n[transport]\nmaxPoolCount = -1\n\n# after\n[transport]\nmaxPoolCount = 5","handlingStrategy":"validation","validationCode":"// startup validation (operator or embedding code)\nif cfg.Transport.MaxPoolCount < 0 {\n    return fmt.Errorf(\"transport.maxPoolCount must be >= 0\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run `frps verify -c frps.toml` in CI before deploy.","Template env-var defaults explicitly (coalesce to the documented default)."],"tags":["go","frp","config","validation","server"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}