locustio/locust · error · ValueError

Invalid time span format. Valid formats: 20, 20s, 3m, 2h, 1h

Error message

Invalid time span format. Valid formats: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc.

What it means

After regex matching, parse_timespan verifies the whole string matched the pattern (group(0) == time_str). Strings containing unsupported characters, units (d/w), signs, or partial matches raise this ValueError with the list of valid formats. Note an all-optional regex can also produce an empty match, which is caught later at line 23.

Source

Thrown at locust/util/timespan.py:20

from datetime import timedelta


def parse_timespan(time_str) -> int:
    """
    Parse a string representing a time span and return the number of seconds.
    Valid formats are: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc.
    """
    if not time_str:
        raise ValueError("Invalid time span format")

    if re.match(r"^\d+$", time_str):
        # if an int is specified we assume they want seconds
        return int(time_str)

    timespan_regex = re.compile(r"((?P<hours>\d+?)h)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?")
    parts = timespan_regex.match(time_str)
    if not parts or parts.group(0) != time_str:
        raise ValueError("Invalid time span format. Valid formats: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc.")
    time_params = {name: int(value) for name, value in parts.groupdict().items() if value}
    if not time_params:
        raise ValueError("Invalid time span format. Valid formats: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc.")
    return int(timedelta(**time_params).total_seconds())

View on GitHub (pinned to f391a716e1)

Solutions

  1. Rewrite the duration using only supported units, e.g. '1d' → '24h', '1.5h' → '1h30m'
  2. Strip whitespace and lowercase the input before passing it
  3. Add your own pre-validation/normalization if you need days or weeks (convert to hours/minutes first)
  4. Update the CLI/config value to one of: 20, 20s, 3m, 2h, 1h20m, 3h30m10s

Example fix

# before
locust --run-time=1d

# after
locust --run-time=24h
Defensive patterns

Strategy: validation

Validate before calling

import re
RUNTIME_RE = re.compile(r'^\d+(?:\d*h)?(?:\d*m)?(?:\d*s)?$')
def is_valid_timespan(s):
    return bool(RUNTIME_RE.fullmatch(s))  # then strip/lower before parse_timespan

Try / catch

try:
    seconds = parse_timespan(run_time.strip().lower())
except ValueError as e:
    log.error('%s — use formats like 20, 20s, 3m, 2h, 1h20m, 3h30m10s', e)
    sys.exit(2)

Prevention

When it happens

Trigger: parse_timespan('1d'), parse_timespan('2H') (uppercase), parse_timespan('3m30') (trailing unitless digits), parse_timespan('-5m'), or any string with whitespace/typos like ' 3m'.

Common situations: Users assuming day/week units are supported (they are not — only h/m/s); uppercase unit letters; stray spaces from config parsing; fractional durations like '1.5h'.

Related errors


AI-assisted analysis of locustio/locust@f391a716e1 (2026-08-29). Data as JSON: /api/errors/3553321d838f4675. Report an issue: GitHub.