locustio/locust · error · LocustError

If you want to change the state of the request, you must pas

Error message

If you want to change the state of the request, you must pass catch_response=True. See http://docs.locust.io/en/stable/writing-a-locustfile.html#validating-responses

What it means

FastResponse.success() is intentionally stubbed to raise LocustError. Manual request state changes are only supported on responses created with catch_response=True; otherwise the method would silently do nothing, so it fails fast with a pointer to the docs.

Source

Thrown at locust/contrib/fasthttp.py:628

    def status_code(self) -> int:
        """
        We override status_code in order to return None if no valid response was
        returned. E.g. in the case of connection errors
        """
        return self._response.get_code() if self._response is not None else 0

    @property
    def ok(self):
        """Returns True if :attr:`status_code` is less than 400, False if not."""
        return self.status_code < 400

    def _content(self):
        if self.headers is None:
            return None
        return super()._content()

    def success(self):
        raise LocustError(
            "If you want to change the state of the request, you must pass catch_response=True. See http://docs.locust.io/en/stable/writing-a-locustfile.html#validating-responses"
        )

    def failure(self, *_args, **_kwargs):
        raise LocustError(
            "If you want to change the state of the request, you must pass catch_response=True. See http://docs.locust.io/en/stable/writing-a-locustfile.html#validating-responses"
        )


class ErrorResponse(FastResponse):  # we're really just pretending to be a FastResponse
    """
    This is used as a dummy response object when geventhttpclient raises an error
    that doesn't have a real Response object attached. E.g. a socket error or similar
    """

    headers: Headers | None = None
    content = None
    status_code = 0

View on GitHub (pinned to f391a716e1)

Solutions

  1. Pass `catch_response=True` to the FastHttpSession request and use the with-block
  2. Remove manual success/failure marking and rely on automatic status handling
  3. Centralize validation in a helper that asserts catch_response was used

Example fix

// before
response = self.client.get("/api")
response.success()  # raises
// after
with self.client.get("/api", catch_response=True) as response:
    response.success()
Defensive patterns

Strategy: validation

Validate before calling

def validated_get(client, url, **kw):
    kw["catch_response"] = True
    return client.get(url, **kw)

Type guard

null

Try / catch

with self.client.get(url, catch_response=True) as resp:
    try:
        resp.success()
    except LocustError as e:
        logger.warning("use catch_response=True: %s", e)

Prevention

When it happens

Trigger: Calling `.success()` (or `.failure()`) on a FastResponse returned from a FastHttpSession request made without `catch_response=True`.

Common situations: Adding response validation to an existing FastHttpUser and forgetting the flag; copying validation code from HttpUser examples without the kwarg; helper functions marking responses unconditionally.

Related errors


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