---
title: "explain why recent requests did not match any expectation"
method: PUT
path: "/mockserver/explainUnmatched"
tags: ["troubleshooting"]
---

# explain why recent requests did not match any expectation

`PUT /mockserver/explainUnmatched`

## Request

- Base URL: `http://localhost:1080`
- URL: `http://localhost:1080/mockserver/explainUnmatched`
- Auth: none declared

Returns a diagnostic report for recently recorded unmatched requests, including the closest-matching expectations and the per-field differences that prevented a match. An optional 'limit' in the body bounds how many unmatched requests are analysed (default 10). With 'suggestFixes' set to true, each of the five closest non-matching expectations also carries a 'suggestedFix': an RFC 6902 JSON patch of that expectation (as PUT /mockserver/retrieve?type=active_expectations returns it) that would make it match the request, the fields it patches and cannot patch, and whether the patched expectation matches. Nothing is applied: to apply a fix, patch the retrieved expectation and send it to PUT /mockserver/expectation, which updates the expectation with the same id. Values the event log redacts are never copied into a patch. With ?narrate=true the response also carries an AI-generated plain-language summary from the configured LLM backend in 'narration'.

## Query parameters

- `narrate` boolean

## Request body

- object
  - `limit` integer: maximum number of recent unmatched requests to analyse
  - `suggestFixes` boolean: add a suggested JSON patch to each of the five closest non-matching expectations

## Response `200`

unmatched-request explanation returned

- ExplainUnmatchedResult: recent requests that matched no expectation, each re-checked against the current expectations (PUT /mockserver/explainUnmatched)
  - `correlationId` string: a new id for this call, not the id of a recorded request
  - `timestamp` string, date-time: when this result was computed
  - `unmatchedRequestCount` integer: how many unmatched requests are listed
  - `truncated` boolean: true when the budget of 500 expectation evaluations ran out, so later unmatched requests are left out and the last one listed may have been compared with only some of the expectations
  - `unmatchedRequests` UnmatchedRequest[]: the most recent unmatched requests, at most limit
    - `timestamp` string: when the request was recorded, as the event log formats it (yyyy-MM-dd HH:mm:ss.SSS)
    - `method` string
    - `path` string
    - `closestExpectations` ExplainedExpectation[]: the expectations compared with the request (at most 50), closest first (fewest differing fields); used-up expectations are left out
      - `expectationId` string
      - `expectationMethod` string
      - `expectationPath` string
      - `position` integer: the expectation's 1-based position in the order MockServer evaluates expectations
      - `priority` integer
      - `reason` 'NAMESPACE' | 'INACTIVE' | 'FIELDS_DIFFER' | 'NOT_OPERATOR' | 'CONVERSATION' | 'SCENARIO_STATE' | 'PERCENTAGE' | 'LOWER_PRIORITY'
      - `explanation` string: why the expectation was passed over, in plain language
      - `matches` boolean: whether the request matches the expectation's request matcher; absent when an earlier gate decided
      - `matchedFieldCount` integer
      - `totalFieldCount` integer
      - `differingFieldCount` integer
      - `differences` object: for each differing field, the differences found
      - `remediation` object: for each differing field, a hint on how to change the expectation
      - `suggestedFix` SuggestedFix: an RFC 6902 JSON patch of an expectation, as PUT /mockserver/retrieve?type=active_expectations returns it, that would make it match the request (PUT /mockserver/explainUnmatched with suggestFixes); nothing is applied
        - `patch` object[]: the patch operations, each under /httpRequest; empty when no field could be patched
          - `op` 'add' | 'remove' | 'replace' | 'test'
          - `path` string: a JSON pointer into the expectation
          - `value` unknown
        - `patchedFields` string[]: the differing fields the patch changes
        - `unpatchedFields` object[]: the differing fields the patch leaves alone, each with the reason
          - `field` string
          - `reason` string
        - `matchesAfterPatch` boolean: whether the patched expectation matches the request; false when the patch is empty
    - `totalExpectationsEvaluated` integer: how many expectations were compared with this request
  - `narration` ExplanationNarration: present only with ?narrate=true: a plain-language summary of the explanation written by the configured LLM backend, or why none is available. It is AI-generated and can be wrong; the other fields are the deterministic facts
    - `available` boolean: whether the LLM returned a summary
    - `aiGenerated` boolean: always true when available; marks the text as written by an LLM, not by MockServer
    - `label` string: a label to show beside the text, saying it is AI-generated and can be wrong
    - `provider` string: the configured LLM provider that wrote the text
    - `model` string: the model that wrote the text, when known
    - `text` string: the summary, at most 4,000 characters including a trailing '...[truncated]' when it was cut
    - `reason` string: when not available, why: llmExplainNarrationEnabled is off, no LLM backend is configured, the LLM failed or returned no text, it did not answer within llmRequestTimeoutMillis plus a 2-second grace, or two narrations are already running

---

[API](https://skmtc.dev/mock-server/apis/mockserver-api.md) · [All operations](https://skmtc.dev/mock-server/apis/mockserver-api/llms.txt) · [OpenAPI document](https://skmtc.dev/mock-server/apis/mockserver-api/revisions/9239b693996e?raw)
