OpenFeign/feign · error · IllegalArgumentException

times must be a non negative number

Error message

times must be a non negative number

What it means

verifyTimes(HttpMethod, String, int) validates its times argument before running any verification. A negative count is meaningless, so an IllegalArgumentException is thrown. It is an immediate programmer-input validation error, not a verification failure.

Solutions

  1. Pass a non-negative times value (0 means verifyNever)
  2. Guard computed values: times = Math.max(0, expectedCount) before calling
  3. If you intend 'never invoked', call verifyNever(method, url) or pass 0

Example fix

// before
mockClient.verifyTimes(HttpMethod.GET, "/users", -1);
// after
mockClient.verifyTimes(HttpMethod.GET, "/users", 0); // or verifyNever
Defensive patterns

Strategy: validation

Validate before calling

if (times < 0) {
  throw new IllegalArgumentException("times must be >= 0 before calling verifyTimes");
}
mockClient.verifyTimes(method, url, times);

Try / catch

try {
  mockClient.verifyTimes(method, url, times);
} catch (IllegalArgumentException e) {
  fail("Bad test input for verifyTimes: " + e.getMessage());
}

Prevention

When it happens

Trigger: Calling mockClient.verifyTimes(method, url, -1) (or any negative int), directly or via verifyOne with a computed negative count.

Common situations: times computed from a loop counter or a size calculation that went negative; copy-paste of -1 sentinel value; test parameterized with bad input.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10). Data as JSON: /api/errors/29158421b2ab3115. Report an issue: GitHub.

Appendix: source

Thrown at mock/src/main/java/feign/mock/MockClient.java:247

  public MockClient add(HttpMethod method, String url, Response response) {
    return this.add(method, url, response.toBuilder());
  }

  public MockClient noContent(HttpMethod method, String url) {
    return add(method, url, HttpURLConnection.HTTP_NO_CONTENT);
  }

  public Request verifyOne(HttpMethod method, String url) {
    return verifyTimes(method, url, 1).get(0);
  }

  public Request verifyOne(RequestKey requestKey) {
    return verifyTimes(requestKey, 1).get(0);
  }

  public List<Request> verifyTimes(final HttpMethod method, final String url, final int times) {
    if (times < 0) {
      throw new IllegalArgumentException("times must be a non negative number");
    }

    if (times == 0) {
      verifyNever(method, url);
      return Collections.emptyList();
    }

    RequestKey requestKey = RequestKey.builder(method, url).build();
    if (!requests.containsKey(requestKey)) {
      throw new VerificationAssertionError(
          "Wanted: '%s' but never invoked! Got: %s", requestKey, requests.keySet());
    }

    List<Request> result = requests.get(requestKey);
    if (result.size() != times) {
      throw new VerificationAssertionError(
          "Wanted: '%s' to be invoked: '%s' times but got: '%s'!",
          requestKey, times, result.size());

View on GitHub (pinned to e2a1e27560)