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

  1. Fix the persisted/computed state so completed >= 0 before constructing CronRepeat
  2. Clamp with max(0, value) when reconstructing from external data
  3. Catch CronJobError during deserialization and reset the record's repeat state to CronRepeat(times=...)
  4. 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

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


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/682208d793fc5af3. Report an issue: GitHub.