{"record":{"id":"ccec1fdc6eaea962","repo":"router-for-me/CLIProxyAPI","slug":"credential-concurrency-limiter-durations-must-be-p","errorCode":null,"errorMessage":"credential concurrency limiter durations must be positive","messagePattern":"credential concurrency limiter durations must be positive","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/credential_concurrency.go","lineNumber":153,"sourceCode":"\tif !c.maxLimitPresent && c.MaxLimit == 0 {\n\t\tc.MaxLimit = maxCredentialConcurrencyLimit\n\t}\n\treturn c\n}\n\n// ValidateCredentialConcurrency validates values intrinsic to a credential concurrency configuration.\nfunc ValidateCredentialConcurrency(cfg CredentialConcurrencyConfig) error {\n\tif cfg.LifecycleConfigRevision < 0 || (cfg.lifecycleConfigRevisionPresent && cfg.LifecycleConfigRevision == 0) {\n\t\treturn fmt.Errorf(\"lifecycle configuration revision must be positive when present\")\n\t}\n\tif cfg.ObservationBarrierRevision < 0 {\n\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 {","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/config/credential_concurrency.go#L135-L171","documentation":"ValidateCredentialConcurrency requires the four limiter durations to be strictly positive: release-flush-interval, release-max-backoff, busy-retry-min, and busy-retry-max. These tune the token/limiter release path (flush cadence, backoff ceiling) and the busy-credential retry window; zero or negative values would stall release processing.","triggerScenarios":"config.yaml credential-concurrency block containing 'release-flush-interval: 0s', 'release-max-backoff: -1s', 'busy-retry-min: 0ms', or 'busy-retry-max: 0s'. Unparseable duration strings that decode to zero also trigger it.","commonSituations":"Tuning retries down to zero to 'disable backoff'; copying the commented example block but leaving some values as placeholders; mixing units (250 vs 250ms) so a bare integer fails duration decoding.","solutions":["Set all four limiter durations positive: release-flush-interval: 500ms, release-max-backoff: 2s, busy-retry-min: 250ms, busy-retry-max: 1s (defaults from config.example.yaml).","Keep release-max-backoff >= release-flush-interval and busy-retry-max >= busy-retry-min to satisfy sibling checks.","Always suffix durations with a unit (ms, s, m).","Remove keys you do not intend to override so defaults apply."],"exampleFix":"# before (config.yaml)\ncredential-concurrency:\n  release-max-backoff: 0s\n  busy-retry-min: 250ms\n  busy-retry-max: 1s\n\n# after\ncredential-concurrency:\n  release-flush-interval: 500ms\n  release-max-backoff: 2s\n  busy-retry-min: 250ms\n  busy-retry-max: 1s","handlingStrategy":"validation","validationCode":"// Go: pre-validate limiter durations.\nfunc limiterDurationsOK(cfg config.CredentialConcurrencyConfig) bool {\n    return cfg.ReleaseFlushInterval > 0 && cfg.ReleaseMaxBackoff > 0 &&\n        cfg.BusyRetryMin > 0 && cfg.BusyRetryMax > 0\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always suffix durations with units (250ms not 250).","Remember defaults: flush 500ms, backoff 2s, retry 250ms–1s.","Validate the whole block together, not field by field."],"tags":["config","validation","credential-concurrency","durations","rate-limiting"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}