skip to content

A WireMock weight-log stub stopped answering after a teammate added a mapping. Why?

level: seniorimportance: must knowfreq 58%

answer

  1. your stub did not change
  2. something else now matches too
  3. the request matched, just not you
  4. check the number, then arrival order
  5. pin with atPriority, not ordering

basics

~20 s

Nothing about your stub changed. The new mapping also matches those requests and sorts ahead of yours, either by carrying a lower atPriority number or by arriving later at equal priority. Your stub still matches; it is no longer first.

solid answer

~40 s

This is a precedence regression, not a matching regression. Your mapping is still registered and still fits the request; a second mapping now fits it too and sorts ahead. There are exactly two ways that happens: the new mapping carries a **lower** `atPriority()` number, or it carries the **same** number — very likely `DEFAULT_PRIORITY`, five, because neither stub called `atPriority()` — and was registered later, so it wins WireMock's insertion-order tie-break. Confirm which by comparing the two mappings' criteria for overlap, then their numbers, then their registration order. The durable fix is to pin your stub with an explicit lower `atPriority()` rather than shuffling `stubFor` calls, because registration order is a property of how the harness executes and the next appended mapping takes the front of the queue for free.

go deeper

for a junior

Know that adding a WireMock mapping can change which existing stub answers, and that a stub which stopped answering is usually still registered and still correct rather than deleted.

for a middle

Explain the two mechanisms precisely: a lower atPriority number wins outright, and an equal number falls through to insertion order where the newest mapping wins. Say which one applies before proposing a fix.

for a senior

Demonstrate the diagnosis and the judgment. Confirm the overlap against one concrete request, resist editing your own stub, and pin the ordering with a number instead of relying on where the registration calls happen to sit.

for a principal

Address why this recurs. Decide whether overlapping mappings are permitted at all, who owns the ordering when two teams register against one server instance, and how a review catches a mapping that silently outranks another team's.

## Nothing changed about your stub The framing of this failure is what makes it hard. Your mapping was not edited, not removed and not invalidated; its criteria still fit the request exactly as they did yesterday. What changed is the *set* it competes in. WireMock gathers every mapping that matched an incoming request, sorts them, and serves the first. Adding a mapping that also matches changes the contents of that collection, and therefore can change which mapping comes first — without touching a single character of yours. That is why the useful first sentence in the diagnosis is a negative one: this is a precedence problem, not a matching problem. Your stub matched. It just was not first. ## The two ways a new mapping takes your requests 1. **It carries a lower `atPriority()` number.** Priority is WireMock's primary sort key and it sorts ascending, so any smaller number goes to the front regardless of when either mapping was registered. A colleague pinning their new stub at `atPriority(1)` will outrank yours at the default five permanently. 2. **It carries the same number and arrived later.** If neither stub calls `atPriority()`, both hold `DEFAULT_PRIORITY`, whose value is five. The priority key separates nothing, WireMock falls through to insertion index descending, and the most recently registered mapping wins. This is the common case, because most stub sets never write a priority number anywhere. Those are the only two possibilities, and distinguishing them tells you what to change. ## Reading the evidence - **Confirm the overlap first.** Line up the two mappings' criteria against one concrete request — say `GET /falconry/v1/birds/kestrel-7/weights` — and check that both really do fit it. If only one fits, precedence is not your problem. - **Compare the numbers.** If the new mapping's number is lower, case one; the ordering is explicit and permanent. - **Compare registration order only if the numbers tie.** Insertion order is never consulted for mappings that differ on priority, so a later mapping losing is proof the numbers already separated them. - **Look at what was actually served.** A response body or status that belongs to the other mapping is direct evidence that a different stub answered, as opposed to nothing answering. - **Do not reach for unmatched-request tooling.** The request matched something, so it is not an unmatched request; treating it as one sends you looking for a matcher bug that does not exist. ## Why "move my stubFor call later" is the wrong fix When both mappings sit at the default, moving your registration after theirs really does restore the old behaviour. It is still the wrong fix, for reasons that show up within weeks: - The ordering now lives in the execution order of fixtures, base classes and setup methods, which no reader of either mapping can see. - The next mapping anyone appends inherits the front of the queue, so the same failure recurs with a new author. - Refactoring that moves a `stubFor` call between a shared setup and a single test changes behaviour with no behavioural change in the diff. - A test that passes alone can fail in a suite, because the set contained different mappings at the moment the request arrived. ## The durable fix - **Pin the mapping that must win with an explicit low `atPriority()` number.** Once your stub holds a smaller number than the competitor, insertion order is never consulted and the ordering survives any reordering of the code. - **Or push the broad mapping down** with a high number if it is the one meant to answer only what nothing else claims. Either end works; what matters is that the ordering is written rather than inherited. - **Or remove the overlap entirely** by tightening one of the two mappings' criteria so they stop competing. This is the strongest outcome when it is available, because it needs no number at all. - **Record the intent next to the number**, naming the mapping it outranks, so the next person to add a competitor sees the claim instead of rediscovering it. ## What this costs when nobody notices The reason this is a senior question rather than a mechanical one is the failure's shape. Nothing errors. The suite may stay green, because the mapping that won can easily return a plausible response — and the test that depended on yours now asserts against someone else's stub. The signal is often a slow drift: a scenario that used to exercise a specific weight-log response is quietly exercising a general one, and the assertion still passes because it was never tight enough to tell them apart. So the judgment being tested is whether you go looking for the *other* mapping at all. A candidate who edits their own stub — loosening its matcher, adding fields, re-recording it — is debugging the wrong artefact. The stub that stopped answering is usually correct; the change that broke it is somewhere else in the set, and precedence is the mechanism that connects them.

  • Can a usage or lifetime cap be used to decide which of two overlapping definitions answers?
    No. A cap bounds how many times or for how long a definition may be used; it does not order two definitions that both match. In MockServer specifically, `Times.exactly(` and `TimeToLive` cap usage count and lifetime, while the precedence control is `Expectation.withPriority(`. Reaching for a cap to settle an overlap solves a different problem.
  • The losing WireMock stub is still registered. Why does that matter for the diagnosis?
    Because it removes the tempting explanations. The mapping was not overwritten, dropped or invalidated, so listing the set will show it present and correct. That is the signal to stop inspecting your own stub and start looking for the other mapping that matches the same request.
  • If your stub is registered later than the competitor and still loses, what does that prove?
    That the two mappings hold different priority numbers, and the competitor's is lower. WireMock only consults insertion order for mappings tied on priority, so a later mapping losing means the priority key already decided. Compare the two numbers rather than the registration sites.

saying these in an interview costs you the question

  • Assumes the stub was overwritten or silently removed
  • Treats a lost overlap as an unmatched-request problem
  • Loosens the stub's own matcher to make it answer again
  • Fixes the ordering by moving stubFor calls around
  • Never looks for the other mapping that matches the request
  • Believes a usage cap decides which overlapping definition wins