scrapy/scrapy · error · ValueError

Interval must be greater than 0

Error message

Interval must be greater than 0

What it means

AsyncioLoopingCall.start() validates the interval argument and raises ValueError when interval <= 0, because scheduling a periodic call at zero or negative periods is meaningless (it would spin the loop).

Source

Thrown at scrapy/utils/asyncio.py:172

    @property
    def running(self) -> bool:
        return self._start_time is not None

    def start(self, interval: float, now: bool = True) -> None:
        """Start calling the function every *interval* seconds.

        :param interval: The interval in seconds between calls.
        :type interval: float

        :param now: If ``True``, also call the function immediately.
        :type now: bool
        """
        if self.running:
            raise RuntimeError("AsyncioLoopingCall already running")

        if interval <= 0:
            raise ValueError("Interval must be greater than 0")

        self.interval = interval
        self._start_time = time.monotonic()
        if now:
            self._call()
        loop = asyncio.get_event_loop()
        self._task = loop.create_task(self._loop())

    def _to_sleep(self) -> float:
        """Return the time to sleep until the next call."""
        assert self.interval is not None
        assert self._start_time is not None
        now = time.monotonic()
        running_for = now - self._start_time
        return self.interval - (running_for % self.interval)

    async def _loop(self) -> None:
        """Run an infinite loop that calls the function periodically."""

View on GitHub (pinned to 06af687662)

Solutions

  1. Pass a positive interval in seconds, e.g. lc.start(30)
  2. Validate/derive the interval defensively: interval = max(float(interval_setting), MIN_INTERVAL) or fail fast with a clear config error
  3. Check that settings keys used for the interval are actually set (self.settings.getfloat('MY_INTERVAL', 60))

Example fix

# before
lc.start(self.settings.getfloat('TICK_INTERVAL', 0))  # 0 -> ValueError

# after
lc.start(self.settings.getfloat('TICK_INTERVAL', 60))
Defensive patterns

Strategy: validation

Validate before calling

interval = self.settings.getfloat('TICK_INTERVAL', 60)
if interval <= 0:
    raise ValueError(f'TICK_INTERVAL must be > 0, got {interval}')

Prevention

When it happens

Trigger: Passing 0, a negative number, or a value computed to <= 0 (e.g. a settings-derived float that parsed to 0) as the interval argument of AsyncioLoopingCall.start().

Common situations: Reading an interval from settings where the key is missing and defaults to 0; float parsing of an empty string or invalid config value yielding 0; passing a timedelta object instead of seconds.

Related errors


AI-assisted analysis of scrapy/scrapy@06af687662 (2026-08-15). Data as JSON: /api/errors/35219af219ef8007. Report an issue: GitHub.