Lightning-AI/pytorch-lightning · error · MisconfigurationException

`Timer(duration={duration!r})` is not a valid duration. Expe

Error message

`Timer(duration={duration!r})` is not a valid duration. Expected a string in the format DD:HH:MM:SS.

What it means

Timer accepts a duration either as a timedelta/dict or as a string that must match DD:HH:MM:SS exactly (regex fullmatch of digits:2digits:2digits:2digits). Any other string format raises this MisconfigurationException in __init__.

Source

Thrown at src/lightning/pytorch/callbacks/timer.py:94

        # query training/validation/test time (in seconds)
        timer.time_elapsed("train")
        timer.start_time("validate")
        timer.end_time("test")

    """

    def __init__(
        self,
        duration: Optional[Union[str, timedelta, dict[str, int]]] = None,
        interval: str = Interval.step,
        verbose: bool = True,
    ) -> None:
        super().__init__()
        if isinstance(duration, str):
            duration_match = re.fullmatch(r"(\d+):(\d\d):(\d\d):(\d\d)", duration.strip())
            if not duration_match:
                raise MisconfigurationException(
                    f"`Timer(duration={duration!r})` is not a valid duration. "
                    "Expected a string in the format DD:HH:MM:SS."
                )
            duration = timedelta(
                days=int(duration_match.group(1)),
                hours=int(duration_match.group(2)),
                minutes=int(duration_match.group(3)),
                seconds=int(duration_match.group(4)),
            )
        elif isinstance(duration, dict):
            duration = timedelta(**duration)
        if interval not in set(Interval):
            raise MisconfigurationException(
                f"Unsupported parameter value `Timer(interval={interval})`. Possible choices are:"
                f" {', '.join(set(Interval))}"
            )
        self._duration = duration.total_seconds() if duration is not None else None
        self._interval = interval

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Use full DD:HH:MM:SS format, e.g. Timer(duration='00:01:30:00') for 1h30m
  2. Or pass a timedelta: Timer(duration=datetime.timedelta(minutes=90))
  3. Or pass a dict: Timer(duration={'minutes': 90})

Example fix

# before
timer = Timer(duration="01:30:00")
# after
from datetime import timedelta
timer = Timer(duration=timedelta(hours=1, minutes=30))
# or Timer(duration="00:01:30:00")
Defensive patterns

Strategy: validation

Validate before calling

import re
from datetime import timedelta

def parse_duration(s):
    if isinstance(s, str):
        if not re.fullmatch(r'(\d+):(\d\d):(\d\d):(\d\d)', s.strip()):
            return timedelta(**{})  # fall back: reject early with your own error
    return s
# simplest: build timedelta directly
Timer(duration=timedelta(hours=1, minutes=30))

Type guard

def is_valid_timer_str(s: str) -> bool:
    import re
    return bool(re.fullmatch(r'(\d+):(\d\d):(\d\d):(\d\d)', s.strip()))

Prevention

When it happens

Trigger: Timer(duration='90:00') (MM:SS), '1 day', '00:30:00' (HH:MM:SS, 3 groups instead of 4), or leading/trailing content that isn't strictly DD:HH:MM:SS.

Common situations: Assuming a friendlier duration parser (ISO8601, '2h'); writing hours:minutes:seconds and forgetting the days field.

Related errors


AI-assisted analysis of Lightning-AI/pytorch-lightning@9fed5c27d2 (2026-08-28). Data as JSON: /api/errors/eca8b38bbabea06d. Report an issue: GitHub.