locustio/locust · error · ValueError

Can't calculate percentile on url with no successful request

Error message

Can't calculate percentile on url with no successful requests

What it means

StatsEntry.percentile() formats a percentile report row and therefore needs at least one successful request; dividing/reading an empty response-time distribution would be meaningless, so it raises ValueError when num_requests is 0.

Source

Thrown at locust/stats.py:659

                    cached = self.response_times_cache[ts]
                    break

        if cached:
            # If we found an acceptable cached response times, we'll calculate a new response
            # times dict of the last 10 seconds (approximately) by diffing it with the current
            # total response times. Then we'll use that to calculate a response time percentile
            # for that timeframe
            return calculate_response_time_percentile(
                diff_response_time_dicts(self.response_times, cached.response_times),
                (self.num_requests - self.num_none_requests) - (cached.num_requests - cached.num_none_requests),
                percent,
            )
        # if time was not in response times cache window
        return None

    def percentile(self) -> str:
        if not self.num_requests:
            raise ValueError("Can't calculate percentile on url with no successful requests")

        tpl = f"%-{str(STATS_TYPE_WIDTH)}s %-{str(STATS_NAME_WIDTH)}s %8d {' '.join(['%6d'] * len(PERCENTILES_TO_REPORT))}"

        return tpl % (
            (self.method or "", self.name)
            + tuple(self.get_response_time_percentile(p) for p in PERCENTILES_TO_REPORT)
            + (self.num_requests,)
        )

    def _cache_response_times(self, t: int) -> None:
        if self.response_times_cache is None:
            self.response_times_cache = OrderedDict()

        self.response_times_cache[t] = CachedResponseTimes(
            response_times=copy(self.response_times),
            num_requests=self.num_requests,
            num_none_requests=self.num_none_requests,
        )

View on GitHub (pinned to f391a716e1)

Solutions

  1. Guard with 'if entry.num_requests:' before calling percentile()
  2. Ensure the request actually succeeded at least once before reporting percentiles
  3. Use entry.get_response_time_percentile only when num_requests > 0 or fall back to a placeholder value like 'N/A'

Example fix

// before
rows.append(entry.percentile())
// after
if entry.num_requests:
    rows.append(entry.percentile())
else:
    rows.append("(no successful requests)")
Defensive patterns

Strategy: validation

Validate before calling

if entry.num_requests == 0:
    return None  # skip percentile report

Try / catch

try:
    row = entry.percentile()
except ValueError:
    row = "N/A"

Prevention

When it happens

Trigger: Calling entry.percentile() on a stats entry for a URL/task that recorded zero successful requests — e.g. only failures, or a request that never fired.

Common situations: Custom console/CSV reporters iterating all entries at the end of a short test where some endpoints never got a 2xx; tests aborted early; entries for requests that only returned errors.

Related errors


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