langchain-ai/deepagents · error · CronJobError

schedule duration must be a positive integer

Error message

schedule duration must be a positive integer

What it means

CronJobError raised by `_positive_int` in libs/talon/deepagents_talon/cron/jobs.py when the numeric part of a schedule duration is not a decimal integer. `_parse_duration_minutes` strips the 'm'/'h' suffix and delegates here; `str.isdecimal()` must be true. This rejects negatives, signs, whitespace, floats, and non-ASCII digits.

Source

Thrown at libs/talon/deepagents_talon/cron/jobs.py:693

def _parse_duration_minutes(value: str) -> int:
    parts = value.split()
    if len(parts) != 1:
        msg = "schedule duration must be a single value such as '30m'"
        raise CronJobError(msg)
    text = parts[0]
    if text.endswith("m"):
        return _positive_int(text[:-1])
    if text.endswith("h"):
        return _positive_int(text[:-1]) * 60
    msg = "schedule duration must use 'm' for minutes or 'h' for hours"
    raise CronJobError(msg)


def _positive_int(value: str) -> int:
    if not value.isdecimal():
        msg = "schedule duration must be a positive integer"
        raise CronJobError(msg)
    number = int(value)
    if number < MIN_GRANULARITY_MINUTES:
        msg = "schedule duration must be at least 1 minute"
        raise CronJobError(msg)
    return number


def _same_origin_scope(left: CronOrigin, right: CronOrigin) -> bool:
    return left.conversation_id == right.conversation_id and left.channel == right.channel


def _coerce_utc(value: datetime | None = None) -> datetime:
    if value is None:
        return datetime.now(UTC)
    if value.tzinfo is None:
        return value.replace(tzinfo=UTC)
    return value.astimezone(UTC)

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Use a plain non-negative decimal integer before the unit: '5m', '60m', '2h'.
  2. Convert fractional hours to whole minutes (e.g. '1.5h' -> '90m').
  3. Strip whitespace and invisible characters from the schedule string before passing it in.

Example fix

// before
parse("1.5h", ...)
parse(" 30m", ...)
// after
parse("90m", ...)
parse("30m", ...)
Defensive patterns

Strategy: validation

Validate before calling

def validate_duration_number(text: str) -> bool:
    unit, num = text[-1:], text[:-1]
    return unit in ("m", "h") and num.isdecimal() and int(num) >= 1

Type guard

def is_decimal_duration(text: str) -> bool:
    return isinstance(text, str) and len(text) > 1 and text[:-1].isdecimal()

Try / catch

try:
    job = parse(schedule)
except CronJobError as exc:
    raise ValueError(f"schedule {schedule!r} must be an integer like '30m' or '2h'") from exc

Prevention

When it happens

Trigger: Passing a schedule like '-5m', ' 10m', '1.5h', '+3h', or 'abc' to `parse`. After stripping the unit suffix, the remaining text fails `isdecimal()` and this error is raised.

Common situations: Hand-edited config files with stray spaces or typo characters; floats used for sub-minute precision (e.g. '0.5h'); copy-paste artifacts like en-dashes or non-breaking spaces in the duration.

Related errors


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