{"record":{"id":"993bf3e0f092ce8f","repo":"router-for-me/CLIProxyAPI","slug":"credential-concurrency-lifecycle-durations-must-be","errorCode":null,"errorMessage":"credential concurrency lifecycle durations must be positive","messagePattern":"credential concurrency lifecycle durations must be positive","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/credential_concurrency.go","lineNumber":150,"sourceCode":"\tif !c.busyRetryMaxPresent && c.BusyRetryMax == 0 {\n\t\tc.BusyRetryMax = defaultBusyRetryMax\n\t}\n\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}","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/config/credential_concurrency.go#L132-L168","documentation":"ValidateCredentialConcurrency requires all four lifecycle durations to be strictly positive: cpa-heartbeat-timeout, cpa-cancel-bound, reclaim-grace, and cleanup-interval. Any of them being zero or negative (e.g. '0s', '-5s', or a null that decodes to zero) triggers this error. These timers drive lease heartbeats, cancellation bounds, reclaim grace, and cleanup sweeps for credential concurrency, so non-positive values would disable the lifecycle.","triggerScenarios":"config.yaml credential-concurrency block with any of: 'cpa-heartbeat-timeout: 0s', 'cpa-cancel-bound: -5s', 'reclaim-grace: 0s', 'cleanup-interval: null'. Setting a duration string the parser cannot handle also decodes to zero and lands here.","commonSituations":"Trying to 'disable' a timer by setting 0s; partial copy of the commented example in config.example.yaml where some values stay at placeholder zero; unit-style durations omitted; a hot-reload edit mid-way through.","solutions":["Set all four lifecycle durations to positive values, e.g. cpa-heartbeat-timeout: 3s, cpa-cancel-bound: 5s, reclaim-grace: 5s, cleanup-interval: 30s (see config.example.yaml).","Remove the individual keys you do not want to override; defaults are positive.","Check for typos in duration strings (e.g. '5sec' is invalid Go duration syntax; use '5s').","Keep the timing safety invariant: node heartbeat timeout + reclaim-grace must exceed cpa-heartbeat-timeout + cpa-cancel-bound."],"exampleFix":"# before (config.yaml)\ncredential-concurrency:\n  cpa-heartbeat-timeout: 0s\n  cpa-cancel-bound: 5s\n  reclaim-grace: 5s\n\n# after\ncredential-concurrency:\n  cpa-heartbeat-timeout: 3s\n  cpa-cancel-bound: 5s\n  reclaim-grace: 5s","handlingStrategy":"validation","validationCode":"// Go: pre-validate lifecycle durations with the same rule.\nfunc lifecycleDurationsOK(cfg config.CredentialConcurrencyConfig) bool {\n    return cfg.CPAHeartbeatTimeout > 0 && cfg.CPACancelBound > 0 &&\n        cfg.ReclaimGrace > 0 && cfg.CleanupInterval > 0\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Copy the commented defaults from config.example.yaml as a known-good baseline.","Never set lifecycle timers to 0s to disable them — omit the key instead.","Use Go duration units (3s, 5s, 30s) exactly."],"tags":["config","validation","credential-concurrency","durations"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}