Skip to content

Reject a negative spawn_rate in /swarm instead of reporting a successful start - #3538

Merged
cyberw merged 1 commit into
locustio:masterfrom
Lesereingrape:fix/swarm-negative-spawn-rate
Oct 4, 2026
Merged

cyberw merged 1 commit into
locustio:masterfrom
Lesereingrape:fix/swarm-negative-spawn-rate

Conversation

@Lesereingrape

Copy link
Copy Markdown
Contributor

Problem

/swarm validated user_count for negativity but only checked spawn_rate for falsiness
(not spawn_rate), so a negative spawn_rate produced {"success": true, "message": "Swarming started"}
and then killed the spawned greenlet with ValueError: spawn_rate must be > 0, got -5.0 from
new_dispatch() — leaving runner.state == ready, runner.user_count == 0 and
unhandled_greenlet_exception == True, with the failure only visible in the log.

Fixes #3537.

Change

locust/web.py — one condition, mirroring the --spawn-rate contract (gt_zero(float) in
locust/argument_parser.py) and the adjacent user_count < 0 check:

-if user_count is None or user_count < 0 or not spawn_rate:
+if user_count is None or user_count < 0 or spawn_rate is None or spawn_rate <= 0:

spawn_rate is None or spawn_rate <= 0 rejects exactly what not spawn_rate rejected (None and
0) plus the negatives, so the existing error message and status are reused unchanged. The
shape-class branch returns before this check, so LoadShape runs that omit spawn_rate are
unaffected.

locust/test/test_web.py — test_swarm_negative_spawn_rate_returns_clean_error(), the missing
counterpart to test_swarm_negative_user_count_returns_clean_error().

How it was checked

On master at 80c03a87, Python 3.11, Windows:

  • New test before the change: FAILED ... AssertionError: True is not false (i.e. /swarm replied
    success: true).
  • pytest locust/test/test_web.py -k swarm -q after the change: 22 passed (includes the
    shape-class and spawn_rate=0 cases).
  • pytest locust/test/test_web.py -q failure set compared against a run of the pristine tip on the
    same interpreter: identical 16 failed / 1 error, all pre-existing Windows-only ones
    (TestWebUIAuth, TestWebUIWithTLS, TestWebUIFullHistory); the only difference is
    40 passed -> 41 passed.
  • ruff check locust/: all checks passed; ruff format --check: already formatted.
  • mypy locust/: 5 errors, byte-identical to the tip baseline (Windows SIGWINCH / resource /
    openpty attribute errors in locust/stats.py, locust/test/__init__.py,
    locust/test/subprocess_utils.py).

Follow-up to #3527 / #3528: the dispatcher now rejects a non-positive rate, this makes the web layer
report it as an error instead of a successful start.

Drafted with AI assistance in this session; no human reviewed it before submission.

The /swarm guard used `not spawn_rate`, which only catches None and 0, so a
negative rate was forwarded to runner.start() and raised inside the spawned
greenlet after the endpoint had already answered success:true.
@cyberw
cyberw merged commit 019e396 into locustio:master Oct 4, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

/swarm reports success:true for a negative spawn_rate, then the run dies in the greenlet

2 participants