router-for-me/CLIProxyAPI · error
credential concurrency busy retry durations must be whole mi
Error message
credential concurrency busy retry durations must be whole milliseconds
What it means
ValidateCredentialConcurrency requires busy-retry-min and busy-retry-max to be exact whole milliseconds (duration % time.Millisecond == 0). Sub-millisecond values such as 250.5µs or 1ms500µs (1500µs is fine, but 1500ns is not) are rejected because the retry limiter schedules on millisecond granularity.
Source
Thrown at internal/config/credential_concurrency.go:159
// 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
}
// ValidateCredentialConcurrencyLifecycle verifies the Home lifecycle timing safety invariant.
func ValidateCredentialConcurrencyLifecycle(nodeHeartbeatTimeout time.Duration, cfg CredentialConcurrencyConfig) error {
if nodeHeartbeatTimeout <= 0 {
return fmt.Errorf("credential concurrency lifecycle durations must be positive")
}
if errValidate := ValidateCredentialConcurrency(cfg); errValidate != nil {
return errValidate
}View on GitHub (pinned to 78f0c4079e)
Solutions
- Round busy-retry-min/max to whole milliseconds, e.g. 250ms and 1s.
- Avoid microsecond (us/µs) and nanosecond (ns) units for these two keys.
- Keep busy-retry-max >= busy-retry-min after rounding.
Example fix
# before (config.yaml) credential-concurrency: busy-retry-min: 250us busy-retry-max: 1s # after credential-concurrency: busy-retry-min: 250ms busy-retry-max: 1s
Defensive patterns
Strategy: validation
Validate before calling
// Go: enforce whole-millisecond retries.
func wholeMillis(d time.Duration) bool { return d%time.Millisecond == 0 }
if !wholeMillis(cfg.BusyRetryMin) || !wholeMillis(cfg.BusyRetryMax) {
return errors.New("busy retry bounds must be whole milliseconds")
} Prevention
- Use ms/s units only for busy-retry values.
- Do not port microsecond-tuned benchmark values into config.
When it happens
Trigger: config.yaml with 'busy-retry-min: 250us', 'busy-retry-max: 1.5ms' expressed via micro/nanosecond units that are not a whole number of milliseconds (e.g. 'busy-retry-min: 1500ns').
Common situations: Aggressive latency tuning copied from a benchmark using microsecond values; unit confusion between us/ms; generated configs emitting floats that yaml decodes into sub-millisecond durations.
Related errors
- credential concurrency lifecycle durations must be positive
- credential concurrency limiter durations must be positive
- credential concurrency release max backoff must not be less
- 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/e069dbb65557d136.
Report an issue: GitHub.