{"record":{"id":"43bec6e87f903ff8","repo":"router-for-me/CLIProxyAPI","slug":"credential-concurrency-release-max-backoff-must-no","errorCode":null,"errorMessage":"credential concurrency release max backoff must not be less than release flush interval","messagePattern":"credential concurrency release max backoff must not be less than release flush interval","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/credential_concurrency.go","lineNumber":156,"sourceCode":"\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 {\n\tif nodeHeartbeatTimeout <= 0 {\n\t\treturn fmt.Errorf(\"credential concurrency lifecycle durations must be positive\")\n\t}","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/config/credential_concurrency.go#L138-L174","documentation":"ValidateCredentialConcurrency enforces release-max-backoff >= release-flush-interval. The release path flushes at a fixed interval and backs off up to a ceiling; a ceiling shorter than the flush cadence is contradictory (the backoff would never take effect), so the pair is rejected.","triggerScenarios":"config.yaml with 'credential-concurrency:\\n  release-flush-interval: 2s\\n  release-max-backoff: 500ms' — any combination where max backoff is numerically smaller than flush interval.","commonSituations":"Tuning flush up for batching while forgetting to raise the backoff ceiling; copying values from different example versions; assuming backoff and flush are independent knobs.","solutions":["Raise release-max-backoff to at least release-flush-interval (e.g. flush 500ms, backoff 2s).","Or lower release-flush-interval below the backoff ceiling.","After fixing, re-validate: both must also be strictly positive and satisfy the whole-millisecond check."],"exampleFix":"# before (config.yaml)\ncredential-concurrency:\n  release-flush-interval: 2s\n  release-max-backoff: 500ms\n\n# after\ncredential-concurrency:\n  release-flush-interval: 500ms\n  release-max-backoff: 2s","handlingStrategy":"validation","validationCode":"// Go: keep backoff ceiling >= flush interval.\nif cfg.ReleaseMaxBackoff < cfg.ReleaseFlushInterval {\n    return errors.New(\"release-max-backoff must be >= release-flush-interval\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When raising flush for batching, raise backoff ceiling first.","Think of the pair as (cadence, ceiling) with ceiling >= cadence."],"tags":["config","validation","credential-concurrency","durations","backoff"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}