{"record":{"id":"9589cb1efdf7fd18","repo":"HKUDS/Vibe-Trading","slug":"retry-max-delay-ms-must-be-at-least-retry-base-del","errorCode":null,"errorMessage":"retry_max_delay_ms must be at least retry_base_delay_ms","messagePattern":"retry_max_delay_ms must be at least retry_base_delay_ms","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/scheduled_research/executor.py","lineNumber":271,"sourceCode":"            if max_consecutive_failures is not None\n            else tuning.vibe_trading_scheduler_max_consecutive_failures\n        )\n        self._retry_base_delay_ms = (\n            retry_base_delay_ms\n            if retry_base_delay_ms is not None\n            else tuning.vibe_trading_scheduler_retry_base_delay_ms\n        )\n        self._retry_max_delay_ms = (\n            retry_max_delay_ms\n            if retry_max_delay_ms is not None\n            else tuning.vibe_trading_scheduler_retry_max_delay_ms\n        )\n        if self._max_consecutive_failures < 1:\n            raise ValueError(\"max_consecutive_failures must be at least 1\")\n        if self._retry_base_delay_ms < 0:\n            raise ValueError(\"retry_base_delay_ms must be non-negative\")\n        if self._retry_max_delay_ms < self._retry_base_delay_ms:\n            raise ValueError(\"retry_max_delay_ms must be at least retry_base_delay_ms\")\n        self._task: asyncio.Task | None = None\n        self._wakeup: asyncio.Event | None = None\n        self._stopping = False\n        self._recovered_stale_running = False\n\n    @property\n    def is_running(self) -> bool:\n        \"\"\"Return whether the background loop task is active.\"\"\"\n        return self._task is not None and not self._task.done()\n\n    def start(self) -> None:\n        \"\"\"Start the background loop.\n\n        Idempotent. When disabled, this is a no-op.\n        \"\"\"\n        if not self._enabled or self.is_running:\n            return\n        self._stopping = False","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/scheduled_research/executor.py#L253-L289","documentation":"The executor enforces retry_max_delay_ms >= retry_base_delay_ms so the backoff cap cannot be below its starting delay — otherwise the exponential sequence would be nonsensical (capped below its first term). Both parameters may also come from tuning defaults, so the check compares the resolved values.","triggerScenarios":"Constructing with retry_base_delay_ms=60000 and retry_max_delay_ms=5000, or where an explicit base delay overrides a smaller default max delay while the max stays at its tuning default.","commonSituations":"Setting only one of the two knobs in config: e.g. raising base delay to 60s while the max stays at a 30s default, breaking the invariant.","solutions":["Raise retry_max_delay_ms to at least retry_base_delay_ms (typically much larger, e.g. base 1s, max 300s).","When overriding base delay in config, override the max delay in the same place.","Use the defaults unless you specifically need custom backoff."],"exampleFix":"# before\nSchedulerExecutor(retry_base_delay_ms=60000, retry_max_delay_ms=5000)\n# after\nSchedulerExecutor(retry_base_delay_ms=1000, retry_max_delay_ms=300000)","handlingStrategy":"validation","validationCode":"retry_base_delay_ms = max(0, int(retry_base_delay_ms))\nretry_max_delay_ms = max(retry_base_delay_ms, int(retry_max_delay_ms))\nexecutor = SchedulerExecutor(retry_base_delay_ms=retry_base_delay_ms,\n                             retry_max_delay_ms=retry_max_delay_ms)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Override base and max delay together in config.","Leave both at defaults unless custom backoff is required."],"tags":["python","scheduler","config-validation","retry"],"backgroundTag":"invalid-configuration-value","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}