OpenFeign/feign · error · VerificationAssertionError

Expected: , but was

Error message

Expected: 
%s,
but was: 
%s

What it means

MockClient's sequential execution mode replays recorded request/response pairs in order. When the incoming request's key does not equal the next expected RequestKey (compared with equalsExtended, which matches url and possibly headers/body), a VerificationAssertionError is thrown showing the expected and actual request keys. It signals the test issued a request different from the next one queued in the mock.

Solutions

  1. Reorder or add MockClient.add(requestKey, response) calls so the next expected RequestKey matches the actual outgoing request
  2. Print both keys and diff method, url, query params, and headers; fix the client request or the recorded RequestKey builder arguments
  3. If order does not matter, use MockClient.imitate() (non-sequential) instead of sequential mode

Example fix

// before
mockClient.add(RequestKey.builder(HttpMethod.GET, "/users/1").build(), okResponse);
// test calls GET /users/2 -> mismatch

// after
mockClient.add(RequestKey.builder(HttpMethod.GET, "/users/2").build(), okResponse);
Defensive patterns

Strategy: validation

Validate before calling

// Before asserting, ensure enqueued keys match the calls your client will make:
RequestKey expected = RequestKey.builder(HttpMethod.GET, url).build();
if (!expected.equalsExtended(actualRequestKey)) {
  throw new IllegalStateException("Mock sequence mismatch: " + expected + " vs " + actualRequestKey);
}

Try / catch

try {
  response = client.call();
} catch (VerificationAssertionError e) {
  // log expected vs actual request keys from e.getMessage()
  throw new AssertionError("Sequential mock request mismatch: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Calling a Feign client built with MockClient.imitateSequential() (or executing sequentially) where the outgoing request's method/url does not match the next recorded RequestKey via equalsExtended.

Common situations: Test sends requests in a different order than they were enqueued; URL built by the target differs (extra/missing path segments or query params); headers or body included in requestKey comparison differ from what was recorded; test forgot to enqueue the request that fires first (e.g. health check).

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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

Appendix: source

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

      responseBuilder = executeAny(request, requestKey);
    }
    responseBuilder.protocolVersion(ProtocolVersion.MOCK);

    return CompletableFuture.completedFuture(responseBuilder.request(request).build());
  }

  private Response.Builder executeSequential(RequestKey requestKey) {
    Response.Builder responseBuilder;
    if (responseIterator == null) {
      responseIterator = responses.iterator();
    }
    if (!responseIterator.hasNext()) {
      throw new VerificationAssertionError("Received excessive request %s", requestKey);
    }

    RequestResponse expectedRequestResponse = responseIterator.next();
    if (!expectedRequestResponse.requestKey.equalsExtended(requestKey)) {
      throw new VerificationAssertionError(
          "Expected: \n%s,\nbut was: \n%s", expectedRequestResponse.requestKey, requestKey);
    }

    responseBuilder = expectedRequestResponse.responseBuilder;
    return responseBuilder;
  }

  private Response.Builder executeAny(Request request, RequestKey requestKey) {
    Response.Builder responseBuilder;
    if (requests.containsKey(requestKey)) {
      requests.get(requestKey).add(request);
    } else {
      requests.put(requestKey, new ArrayList<>(Arrays.asList(request)));
    }

    responseBuilder = getResponseBuilder(request, requestKey);
    return responseBuilder;
  }

View on GitHub (pinned to e2a1e27560)