langchain-ai/deepagents · error · CronJobError
repeat completed count cannot be negative
Error message
repeat completed count cannot be negative
What it means
CronRepeat.__post_init__ enforces that the completed attempt counter is non-negative; constructing a CronRepeat with completed < 0 raises this CronJobError at instantiation. The completed count is internal bookkeeping for how many runs of a capped recurring job have finished, so a negative value indicates corrupted or miscalculated state.
Source
Thrown at libs/talon/deepagents_talon/cron/jobs.py:203
class CronRepeat:
"""Optional cap for recurring cron jobs.
Args:
times: Maximum scheduled attempts, or `None` for unlimited recurrence.
completed: Number of intervals already claimed for execution.
"""
times: int | None = None
completed: int = 0
def __post_init__(self) -> None:
"""Validate repeat cap values."""
if self.times is not None and self.times < 1:
msg = "repeat cap must be at least 1"
raise CronJobError(msg)
if self.completed < 0:
msg = "repeat completed count cannot be negative"
raise CronJobError(msg)
def claim(self) -> CronRepeat:
"""Return repeat state after claiming one scheduled attempt.
Returns:
Updated repeat state.
"""
return replace(self, completed=self.completed + 1)
@property
def exhausted(self) -> bool:
"""Whether the repeat cap has been reached."""
return self.times is not None and self.completed >= self.times
def to_dict(self) -> CronRepeatDict:
"""Serialize this repeat state for disk storage.
Returns:View on GitHub (pinned to a1af029e6e)
Solutions
- Fix the persisted/computed state so completed >= 0 before constructing CronRepeat
- Clamp with max(0, value) when reconstructing from external data
- Catch CronJobError during deserialization and reset the record's repeat state to CronRepeat(times=...)
- Audit the code path that decrements completed to ensure it never subtracts more than available
Example fix
// before repeat = CronRepeat(times=3, completed=done - fetched) # may go negative // after repeat = CronRepeat(times=3, completed=max(0, done - fetched))
Defensive patterns
Strategy: validation
Validate before calling
def can_construct_repeat(times, completed) -> bool:
return completed >= 0 and (times is None or times >= 1)
if not can_construct_repeat(times, completed):
completed = max(0, completed) # clamp before constructing Type guard
def has_valid_completed(value: object) -> bool:
return isinstance(value, int) and not isinstance(value, bool) and value >= 0 Try / catch
try:
repeat = CronRepeat(times=t, completed=stored_completed)
except CronJobError:
repeat = CronRepeat(times=t, completed=0) # reset corrupt counter Prevention
- Clamp counters with max(0, value) when deserializing persisted state
- Never subtract unvalidated external counts from completed
- Treat negative counters as corrupt data and reset rather than propagate
- Validate state after migrations or manual edits of persisted job records
When it happens
Trigger: Constructing CronRepeat(times=5, completed=-1) (or any negative completed) directly, deserializing persisted job records whose stored completed count is negative, or computing completed via subtraction that underflows.
Common situations: Hand-editing or migrating persisted cron job JSON where the counter went negative; restoring from a backup with corrupt state; arithmetic bugs like completed - fetched_count when fetched exceeds completed.
Related errors
- `expires_at` is only meaningful when `logged_in` is True.
- `is_expired` is only meaningful when `logged_in` is True.
- cron schedules must be at least 1 minute
- schedule must look like 'in 30m' or 'every 15m'
- repeat cap must be at least 1
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/682208d793fc5af3.
Report an issue: GitHub.