{"record":{"id":"2b7048734e8785b4","repo":"router-for-me/CLIProxyAPI","slug":"credential-concurrency-max-limit-must-be-between-1","errorCode":null,"errorMessage":"credential concurrency max limit must be between 1 and %d","messagePattern":"credential concurrency max limit must be between 1 and (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/credential_concurrency.go","lineNumber":165,"sourceCode":"\t\treturn fmt.Errorf(\"observation barrier revision must not be negative\")\n\t}\n\tif cfg.CPAHeartbeatTimeout <= 0 || cfg.CPACancelBound <= 0 || cfg.ReclaimGrace <= 0 || cfg.CleanupInterval <= 0 {\n\t\treturn fmt.Errorf(\"credential concurrency lifecycle durations must be positive\")\n\t}\n\tif cfg.ReleaseFlushInterval <= 0 || cfg.ReleaseMaxBackoff <= 0 || cfg.BusyRetryMin <= 0 || cfg.BusyRetryMax <= 0 {\n\t\treturn fmt.Errorf(\"credential concurrency limiter durations must be positive\")\n\t}\n\tif cfg.ReleaseMaxBackoff < cfg.ReleaseFlushInterval {\n\t\treturn fmt.Errorf(\"credential concurrency release max backoff must not be less than release flush interval\")\n\t}\n\tif cfg.BusyRetryMin%time.Millisecond != 0 || cfg.BusyRetryMax%time.Millisecond != 0 {\n\t\treturn fmt.Errorf(\"credential concurrency busy retry durations must be whole milliseconds\")\n\t}\n\tif cfg.BusyRetryMax < cfg.BusyRetryMin {\n\t\treturn fmt.Errorf(\"credential concurrency busy retry max must not be less than busy retry min\")\n\t}\n\tif cfg.MaxLimit < 1 || cfg.MaxLimit > maxCredentialConcurrencyLimit {\n\t\treturn fmt.Errorf(\"credential concurrency max limit must be between 1 and %d\", maxCredentialConcurrencyLimit)\n\t}\n\treturn nil\n}\n\n// ValidateCredentialConcurrencyLifecycle verifies the Home lifecycle timing safety invariant.\nfunc ValidateCredentialConcurrencyLifecycle(nodeHeartbeatTimeout time.Duration, cfg CredentialConcurrencyConfig) error {\n\tif nodeHeartbeatTimeout <= 0 {\n\t\treturn fmt.Errorf(\"credential concurrency lifecycle durations must be positive\")\n\t}\n\tif errValidate := ValidateCredentialConcurrency(cfg); errValidate != nil {\n\t\treturn errValidate\n\t}\n\tleft, leftOverflow := addCredentialConcurrencyDuration(nodeHeartbeatTimeout, cfg.ReclaimGrace)\n\tright, rightOverflow := addCredentialConcurrencyDuration(cfg.CPAHeartbeatTimeout, cfg.CPACancelBound)\n\tif leftOverflow || rightOverflow {\n\t\treturn fmt.Errorf(\"credential concurrency lifecycle timing safety invariant overflows\")\n\t}\n\tif left <= right {","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/config/credential_concurrency.go#L147-L183","documentation":"ValidateCredentialConcurrency bounds 'credential-concurrency.max-limit' to [1, maxCredentialConcurrencyLimit]. The limit caps concurrent requests per credential; zero, negative, or astronomically large values are rejected. Note the normalization step: if the key is absent, MaxLimit defaults to the ceiling — so this error only fires when the key is present with an out-of-range value (0 or below, or above the hard cap).","triggerScenarios":"config.yaml with 'credential-concurrency:\\n  max-limit: 0', 'max-limit: -5', or a value above maxCredentialConcurrencyLimit (the hard cap, e.g. 1000000 as shown in config.example.yaml).","commonSituations":"Setting max-limit: 0 intending 'unlimited' (the ceiling default applies only when the key is absent); scaling values beyond the hard cap to disable throttling; templated configs emitting 0 for unset integers.","solutions":["Remove the max-limit key entirely to get the default hard cap, or set it between 1 and the cap (e.g. max-limit: 1000000).","Never use 0 or negatives to mean 'unlimited'.","Check config.example.yaml line 66 for the allowed ceiling and stay within it."],"exampleFix":"# before (config.yaml)\ncredential-concurrency:\n  max-limit: 0\n\n# after: key removed (defaults to hard cap)\ncredential-concurrency:\n  cpa-heartbeat-timeout: 3s","handlingStrategy":"validation","validationCode":"// Go: bound max-limit to the hard cap (mirror of the library check).\nconst maxCap = int64(1000000) // keep in sync with maxCredentialConcurrencyLimit\nif cfg.MaxLimit < 1 || cfg.MaxLimit > maxCap {\n    return fmt.Errorf(\"max-limit must be in [1, %d]\", maxCap)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Omit max-limit for the default ceiling; do not use 0 for 'unlimited'.","Templates: skip the key when the variable is unset."],"tags":["config","validation","credential-concurrency","limits"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}