router-for-me/CLIProxyAPI · error
credential concurrency lifecycle durations must be positive
Error message
credential concurrency lifecycle durations must be positive
What it means
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.
Source
Thrown at internal/config/credential_concurrency.go:150
if !c.busyRetryMaxPresent && c.BusyRetryMax == 0 {
c.BusyRetryMax = defaultBusyRetryMax
}
if !c.maxLimitPresent && c.MaxLimit == 0 {
c.MaxLimit = maxCredentialConcurrencyLimit
}
return c
}
// ValidateCredentialConcurrency validates values intrinsic to a credential concurrency configuration.
func ValidateCredentialConcurrency(cfg CredentialConcurrencyConfig) error {
if cfg.LifecycleConfigRevision < 0 || (cfg.lifecycleConfigRevisionPresent && cfg.LifecycleConfigRevision == 0) {
return fmt.Errorf("lifecycle configuration revision must be positive when present")
}
if cfg.ObservationBarrierRevision < 0 {
return fmt.Errorf("observation barrier revision must not be negative")
}
if cfg.CPAHeartbeatTimeout <= 0 || cfg.CPACancelBound <= 0 || cfg.ReclaimGrace <= 0 || cfg.CleanupInterval <= 0 {
return fmt.Errorf("credential concurrency lifecycle durations must be positive")
}
if cfg.ReleaseFlushInterval <= 0 || cfg.ReleaseMaxBackoff <= 0 || cfg.BusyRetryMin <= 0 || cfg.BusyRetryMax <= 0 {
return fmt.Errorf("credential concurrency limiter durations must be positive")
}
if cfg.ReleaseMaxBackoff < cfg.ReleaseFlushInterval {
return fmt.Errorf("credential concurrency release max backoff must not be less than release flush interval")
}
if cfg.BusyRetryMin%time.Millisecond != 0 || cfg.BusyRetryMax%time.Millisecond != 0 {
return fmt.Errorf("credential concurrency busy retry durations must be whole milliseconds")
}
if cfg.BusyRetryMax < cfg.BusyRetryMin {
return fmt.Errorf("credential concurrency busy retry max must not be less than busy retry min")
}
if cfg.MaxLimit < 1 || cfg.MaxLimit > maxCredentialConcurrencyLimit {
return fmt.Errorf("credential concurrency max limit must be between 1 and %d", maxCredentialConcurrencyLimit)
}
return nil
}View on GitHub (pinned to 78f0c4079e)
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.
Example fix
# before (config.yaml) credential-concurrency: cpa-heartbeat-timeout: 0s cpa-cancel-bound: 5s reclaim-grace: 5s # after credential-concurrency: cpa-heartbeat-timeout: 3s cpa-cancel-bound: 5s reclaim-grace: 5s
Defensive patterns
Strategy: validation
Validate before calling
// Go: pre-validate lifecycle durations with the same rule.
func lifecycleDurationsOK(cfg config.CredentialConcurrencyConfig) bool {
return cfg.CPAHeartbeatTimeout > 0 && cfg.CPACancelBound > 0 &&
cfg.ReclaimGrace > 0 && cfg.CleanupInterval > 0
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- credential concurrency limiter durations must be positive
- credential concurrency release max backoff must not be less
- credential concurrency busy retry durations must be whole mi
- credential concurrency lifecycle timing safety invariant ove
- lifecycle configuration revision must be positive when prese
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/993bf3e0f092ce8f.
Report an issue: GitHub.