Troubleshooting Index
Start here when something is wrong and you don't yet know which page explains it. Find your symptom below, do the one diagnostic step listed, then follow the link for the full fix.
Symptom Index
| Symptom | Likely causes | Diagnostic step |
|---|---|---|
| My request returns 404 | No expectation matches the request; the expectation expired or was cleared; or an expectation matched but its template/action threw | x-mockserver-closest-match-hint response header, or PUT /mockserver/debugMismatch |
| The expectation matched the wrong one | Two expectations both match; priority or insertion order picked the other one | PUT /mockserver/retrieve?type=LOGS — find the "matched expectation" entry |
| Forwarding returns 502 / connection refused | Upstream host unresolvable, refusing or not answering, upstream proxy unreachable, a pooled connection closed, TLS failure to the upstream, HTTP/2 error, or an undecodable upstream response | Read the 502 response body — it names the cause |
| TLS handshake fails | Client doesn't trust MockServer's CA, empty JVM trust store, protocol mismatch, expired certificate, missing client certificate (mTLS) | MockServer's WARN log line naming the failed handshake and its probable cause |
| The dashboard is empty | Dashboard pointed at the wrong port, log cleared/reset, maxLogEntries set too low, request filter hiding everything |
PUT /mockserver/retrieve?type=LOGS against the same host/port the dashboard is pointed at |
| A verification fails unexpectedly | The request never arrived, arrived with different fields, or arrived a different number of times than expected | The verification failure's closest-request diff (detailedVerificationFailures, default true) |
| LLM mock returns the wrong shape | The expectation's llmResponse.provider or completion.streaming is set to the wrong value — neither is detected from the request |
Check the expectation's own provider and completion.streaming fields |
| The container won't start | Host port already in use (Docker refuses to start it), missing TLS certificate files, Docker health check failing | Docker's own error on docker run for a port clash; otherwise docker logs on the container |
| A configuration property seems to be ignored | A typo in the property name, or the wrong form (system property vs. environment variable vs. properties file) | The startup WARN log: unrecognised MockServer configuration ... it is not a known configuration property and will be ignored (check for a typo) |
| A response template errors or produces the wrong output | Template syntax error, missing variable, wrong template engine selected | A 500 with an x-mockserver-template-error: true header and the template error as its body, and the log entry "Exception: ... transforming template"; see Response Templates |
| An OpenAPI specification fails to load | Invalid YAML/JSON, unresolved $ref, wrong file path or URL |
The parser error messages returned in the PUT /mockserver/expectation (OpenAPI form) response body |
My request returns 404
MockServer returns 404 when no active expectation matches the request. Three tools tell you why in one step, before you open the full checklist:
- The response carries an
x-mockserver-closest-match-hintheader (enabled by default,closestMatchHintEnabled) naming the closest-matching expectation and what differed. PUT /mockserver/debugMismatchre-runs the request against every active expectation and returns, per expectation, which fields matched and which didn't — see Programmatic Mismatch Debugging.PUT /mockserver/explainUnmatchedre-evaluates recent unmatched requests already recorded in the log against the current expectations and ranks the closest matches, within a bounded evaluation budget. With"suggestFixes": trueit also suggests the smallest change to each close expectation that would make it match, which you can preview and apply from the dashboard — see Suggested Fixes.
For the full step-by-step checklist (is the expectation still active, did the request arrive, common pitfalls like trailing slashes or regex metacharacters), see Troubleshooting Matching.
The request matched, but you still got a 404
A 404 is not always a non-match: if the matched expectation's response action throws while building the response — for example a class callback that fails, or a template that fails when templateFailureAsServerError is false (a failed template answers 500 by default) — MockServer answers with a plain 404 with no body, because the failure is handled by the same generic exception path a non-match uses. In this case no closest-match hint header appears, since one was matched. The only trace is in the log: an entry whose message contains Exception: and, for a template, transforming template. Retrieve the log and look for that text before assuming the expectation itself did not match:
curl -X PUT "http://localhost:1080/mockserver/retrieve?type=LOGS"
The expectation matched the wrong one
When more than one expectation matches a request, MockServer picks one by priority, then insertion order. Retrieve the log to see which expectation id actually matched:
curl -X PUT "http://localhost:1080/mockserver/retrieve?type=LOGS&format=LOG_ENTRIES"
The default plain-text log format writes only a timestamp and message per entry, so it never shows the entry's type. Add &format=LOG_ENTRIES to get structured entries and read the type field for EXPECTATION_MATCHED — or, without that parameter, search the plain-text log for the words "matched expectation". Either way the entry names the expectation id and path that won. Compare that expectation's priority field and its position among PUT /mockserver/retrieve?type=ACTIVE_EXPECTATIONS against the one you expected to match — see Creating Expectations for how priority and insertion order are used, and Logging & Debugging for retrieving active expectations.
Forwarding returns 502 / connection refused
When MockServer forwards a request and the upstream call fails, it answers with 502 whose body names the cause and, for a connection that could not be made, what to change:
- Connection failure — "upstream host name could not be resolved: ...", "upstream refused the connection: ...", "connection to the upstream timed out: ...", "upstream address could not be reached (no route to it): ...", "upstream proxy set by forwardHttpProxy could not be reached (...): ...", "upstream closed the pooled keep-alive connection ...", or "MockServer ran out of local ports or open files ..." (a forward that points back at MockServer itself is the usual cause of the last one). The full list, with what to change for each, is in Why a Forward Failed (502 Bad Gateway)
- Set-up failure — "connection to the upstream could not be set up: ..." (a configuration problem on MockServer's side, such as a forwardProxyPrivateKey or forwardProxyCertificateChain that is not valid PEM)
- TLS failure — "TLS with the upstream failed: ..."
- HTTP/2 error — "HTTP/2 error from the upstream: ..."
- Undecodable response — "response from the upstream could not be decoded: ..."
A 502 with an empty body is a failure MockServer could not classify; set logLevel to TRACE to see the underlying exception.
Read the 502 body first; it tells you which of the above you're dealing with. For slow or intermittently slow upstreams rather than outright failures, see the timing fields on retrieved request-response pairs in Request Forwarding Timings and Network Latency Debugging.
TLS handshake fails
MockServer logs a client's failed TLS handshake as a WARN (once per client address, then DEBUG for repeats) naming the reason and a probable cause, for example the client does not trust MockServer's Certificate Authority. Set logLevel to DEBUG to see every failed handshake.
The full troubleshooting table — untrusted CA, empty JVM trust store on minimal Docker images, protocol mismatch, expired certificates, mTLS certificate chain problems, 426 Upgrade Required, bad certificate — is at HTTPS & TLS → TLS Troubleshooting.
The dashboard is empty
The dashboard reads from the same in-memory log and expectation store as the REST API. If it looks empty, confirm the underlying data is actually there before assuming the UI is broken:
curl -X PUT "http://localhost:1080/mockserver/retrieve?type=LOGS"
curl -X PUT "http://localhost:1080/mockserver/retrieve?type=ACTIVE_EXPECTATIONS"
If that also returns nothing, the log or expectations were cleared or reset (see Clearing & Resetting), or maxLogEntries is set very low and entries were evicted (see Retrieving Recorded Logs). If the REST call above returns data but the dashboard still shows nothing, the dashboard is most likely pointed at a different host/port, or a request filter in the UI is hiding the entries — see Launch UI and Request Filter.
A verification fails unexpectedly
Verification failures include the closest recorded request's diff by default (detailedVerificationFailures, default true), showing exactly which field didn't match the expected request — or that no request matching that count arrived at all. See Verifying Requests & Responses for the verification API, and confirm the request actually reached MockServer with PUT /mockserver/retrieve?type=REQUESTS before assuming the verification itself is wrong.
LLM mock returns the wrong shape
MockServer does not detect the provider from the request. The expectation's own llmResponse.provider field sets it, and whether the response streams is decided by the expectation's completion.streaming field — neither comes from the request. If the shape is wrong, the expectation itself is most likely configured with the wrong provider or streaming flag, not MockServer guessing wrong:
- A missing or null
providergives a 400 with body{"error":"unsupported LLM provider: null", ...}rather than a wrong shape — if you're seeing that, addproviderto the expectation instead of debugging the shape. - A mismatched
providerproduces a response shaped for the wrong API (wrong field names, wrong envelope). - A mismatched
completion.streamingproduces a single JSON body when you expected Server-Sent Events, or vice versa.
See Mock LLM APIs → Supported Providers for the full list of provider values, and Streaming Responses for how completion.streaming changes the response shape.
The container won't start
MockServer's Docker images are built on distroless base images — there is no shell and no curl inside the container, so you cannot docker exec -it ... sh into it to poke around. Start with:
docker logs <container>
Common causes: a configured TLS certificate/key file path that does not exist in the container (check your volume mounts) — this shows up in docker logs. A host-port clash on docker run -p, by contrast, is reported by Docker itself when it refuses to start the container (the container never starts, so there is nothing in docker logs). If MockServer itself finds the port already taken (for example by another process when running without Docker's own port mapping), its own log message names the address it tried to bind and suggests lsof -nP -iTCP:<port> -sTCP:LISTEN to find what is using it — it does not name the other process itself. The image ships a built-in health check binary (/mockserver-healthcheck) that calls PUT /mockserver/status — see Docker Health Checks for how it works and how to wire it into Compose, Kubernetes or ECS.
A configuration property seems to be ignored
An unrecognised mockserver.* system property or MOCKSERVER_* environment variable is not rejected — it logs a WARN at startup and is otherwise ignored:
unrecognised MockServer configuration <key> - it is not a known configuration property and will be ignored (check for a typo)
Check the startup log for this line first. Then confirm you're using the right form for where you're setting it (system property, environment variable, or properties file key) — see Configuration for the full reference, and retrieve the currently effective configuration with GET /mockserver/configuration (see Retrieving & Updating Configuration).
A response template errors or produces the wrong output
A template failure answers 500 with an x-mockserver-template-error: true header and the template error, with its line and column when the engine reports them, as a plain-text body; the log also records it as "Exception: ... transforming template". With templateFailureAsServerError=false the client gets a plain 404 with no body instead (see My request returns 404). Confirm which template engine the expectation uses (Velocity, Mustache or JavaScript) and check the syntax against that engine's own rules — see Response Templates.
An OpenAPI specification fails to load
Loading an OpenAPI specification as an expectation returns the Swagger/OpenAPI parser's own messages in the PUT /mockserver/expectation response body when the spec is invalid (bad YAML/JSON, an unresolved $ref, or an unreachable path/URL). Read that response body first — it names the parser error. See OpenAPI & WSDL for how specifications are loaded and matched.
Related Pages
- Logging & Debugging — retrieving expectations, requests, logs and metrics
- Troubleshooting Matching — the full 404 debugging checklist and common matching pitfalls
- HTTPS & TLS → TLS Troubleshooting
- Debugging HTTP Traffic with AI Assistants — using the MCP tools to debug mismatches conversationally