{"record":{"id":"7eaa84d83593a316","repo":"langchain-ai/deepagents","slug":"repeat-cap-must-be-at-least-1","errorCode":null,"errorMessage":"repeat cap must be at least 1","messagePattern":"repeat cap must be at least 1","errorType":"validation","errorClass":"CronJobError","httpStatus":null,"severity":"error","filePath":"libs/talon/deepagents_talon/cron/jobs.py","lineNumber":200,"sourceCode":"\n\n@dataclass(frozen=True, slots=True)\nclass CronRepeat:\n    \"\"\"Optional cap for recurring cron jobs.\n\n    Args:\n        times: Maximum scheduled attempts, or `None` for unlimited recurrence.\n        completed: Number of intervals already claimed for execution.\n    \"\"\"\n\n    times: int | None = None\n    completed: int = 0\n\n    def __post_init__(self) -> None:\n        \"\"\"Validate repeat cap values.\"\"\"\n        if self.times is not None and self.times < 1:\n            msg = \"repeat cap must be at least 1\"\n            raise CronJobError(msg)\n        if self.completed < 0:\n            msg = \"repeat completed count cannot be negative\"\n            raise CronJobError(msg)\n\n    def claim(self) -> CronRepeat:\n        \"\"\"Return repeat state after claiming one scheduled attempt.\n\n        Returns:\n            Updated repeat state.\n        \"\"\"\n        return replace(self, completed=self.completed + 1)\n\n    @property\n    def exhausted(self) -> bool:\n        \"\"\"Whether the repeat cap has been reached.\"\"\"\n        return self.times is not None and self.completed >= self.times\n\n    def to_dict(self) -> CronRepeatDict:","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/talon/deepagents_talon/cron/jobs.py#L182-L218","documentation":"CronRepeat.__post_init__ validates that the optional repeat cap (times) is at least 1 when provided; passing 0 or a negative number raises this CronJobError immediately at dataclass construction. A repeat cap of 0 or less is meaningless — a recurring job must run at least once per cap, so the library refuses to construct the invalid state.","triggerScenarios":"Constructing CronRepeat(times=0) or CronRepeat(times=-1) directly, or calling create_job/edit_job with repeat_times=0 or repeat_times=<negative int> on a recurring schedule.","commonSituations":"Using 0 as a 'no repeat' sentinel (the library expects None for unlimited instead); decrementing a counter in a loop until it hits 0 before passing it; config files where a cap was omitted and a 0 default filled in; off-by-one math producing -1.","solutions":["Pass repeat_times >= 1, or pass None to indicate an uncapped recurring job","Replace 0-as-sentinel logic with None so validation passes and semantics are correct","Validate user-supplied repeat counts (int and >= 1) before constructing CronRepeat or calling create_job/edit_job","Catch CronJobError around create_job/edit_job and re-prompt or clamp the value"],"exampleFix":"// before\nrepeat = CronRepeat(times=0)  # raises\n// after\nrepeat = CronRepeat(times=None)  # unlimited\n# or a real cap\nrepeat = CronRepeat(times=1)","handlingStrategy":"validation","validationCode":"def is_valid_repeat_cap(times) -> bool:\n    return times is None or (isinstance(times, int) and times >= 1)\n\nif not is_valid_repeat_cap(repeat_times):\n    raise ValueError(\"repeat cap must be None (unlimited) or an integer >= 1\")","typeGuard":"def is_repeat_cap(value: object) -> bool:\n    return value is None or (isinstance(value, int) and not isinstance(value, bool) and value >= 1)","tryCatchPattern":"try:\n    job = store.create_job(..., repeat_times=times)\nexcept CronJobError as exc:\n    if \"repeat cap\" in str(exc):\n        job = store.create_job(..., repeat_times=None)\n    else:\n        raise","preventionTips":["Use None (not 0) to mean 'no cap'","Validate user-supplied counts as int >= 1 before constructing CronRepeat","Guard loop/decrement math so counters never reach 0 or below before being passed as a cap"],"tags":["validation","cron","dataclass"],"backgroundTag":"invalid-repeat-cap","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}