Repository navigation
chore(deps): update dependency org.mock-server:mockserver-netty-no-dependencies to v9 - #2561
Merged
renovate[bot] merged 1 commit intoOct 16, 2026
Conversation
renovate
Bot
requested review from
dhoard,
fstab,
jaydeluca and
zeitlinger
as code owners
October 16, 2026 00:39
renovate
Bot
force-pushed
the
renovate/org.mock-server-mockserver-netty-no-dependencies-9.x
branch
from
October 16, 2026 06:44
ec04276 to
fc6e5d0
Compare
zeitlinger
approved these changes
Oct 16, 2026
renovate
Bot
deleted the
renovate/org.mock-server-mockserver-netty-no-dependencies-9.x
branch
October 16, 2026 07:06
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
This PR body was truncated due to platform limits.
This PR contains the following updates:
8.0.0→9.0.0Release Notes
mock-server/mockserver-monorepo (org.mock-server:mockserver-netty-no-dependencies)
v9.0.0This release delivers a sustained performance and memory programme alongside data-integrity fixes under load, plus a large set of LLM-provider correctness fixes, dashboard improvements, and client-library parity work. Headline numbers from the single-load-generator benchmark on the same six-core rig (builds 420 and 464): the healthy ceiling rises from 39,033 to 57,149 req/s and the peak from 43,671 to 59,905 req/s, with p95 at 32,000 req/s falling from 56.6 ms to 0.44 ms on the new ZGC default in the Docker images; event-log retained heap at 20,000 entries falls from 429 MB to 61 MB; Docker image download shrinks ~23%; and instance shutdown drops from ~107 ms to near zero. 22 BREAKING changes affect HTTP/3, DNS mocking, binary (non-HTTP) proxying and binary expectation matching while proxying, template-failure response codes,
maxLoggedMatchFailures's default, initialisation-fileidconflicts, the Node client's TypeScript typings andexportsmap,LOG_ENTRIESlog output, control-plane error handling and mTLS, the Rust client's enums, verification-failure wording, responsestatusCodevalidation, AsyncAPI and response/OpenAPI verification, GenAI trace span names, the Node client's recorded-request typings, and the Go client/Testcontainers module's/v9module paths — see Upgrading from 8.0.0 and theBREAKINGentries under Changed. For a per-change migration list, see the upgrade guide at https://www.mock-server.com/mock_server/upgrading_to_9.html."Before" is perf build 420 (commit
d568695, 2026-09-24, JDK 17.0.20, G1 collector), measured nine days after the 8.0.0 tag and already carrying some of this release's own work, since 8.0.0 itself was never measured on this rig. "After" is perf build 464 (commitefdc522, 2026-09-27, JDK 25, ZGC), the performance page's single-load-generator figures; the page's headline is now a different, multi-generator measurement (see Changed). Both are comparable with each other but not with any benchmark published after this release.Upgrading from 8.0.0
/v9module paths (the Go module proxy refused their 8.0.0 tags) — rungo get github.com/mock-server/mockserver-monorepo/mockserver-client-go/v9(and the Testcontainers module's/v9path if you use it) and change yourimports from the
/v7/unsuffixed paths to the/v9ones; see Changed.http3Portset): the QUIC native library now ships separately — use the-jar-with-dependencies-http3jar or themockserver/mockserver:<version>-http3Docker image (latest-http3,snapshot-http3; Helm:image.variant=http3), and a server that cannot serve HTTP/3 (missingnative, or the port unusable) now refuses to start instead of silently falling back.
dnsEnabled=true): MockServer now refuses to start if itsdnsPortcannot be bound, instead of logging a warning and running without DNS. LeavednsPortat its default of0to let the OS pick a free port, or setdnsEnabled=false.mockserver-client/llm: the deep-import typings no longer declare a default export; import frommockserver-clientitself, useimport llm = require(...)/import * as llm from ..., or turn onesModuleInterop(see Changed).forwardBinaryRequestsWithoutWaitingForResponsesetting (a value still set is ignored, with a warning); remove it from your configuration.message/argumentsofLOG_ENTRIESoutput (including the MCPretrieve_logs/raw_retrievetools): read it from the entry'shttpRequest/httpResponseinstead —message/argumentsnow refer to that request/response by a short formsuch as
"POST /orders"or"201".400as any failure, or catching the Java client'sIllegalArgumentExceptionfor non-input failures: an unexpected server-side fault is now a500with a generic message and correlation id;400is now reserved for requests MockServer genuinely rejects. TheJava client's
retrieveLogsByCorrelationIdandretrieveActiveExpectations(requestDefinition, format)now throw instead of returning the error's text.mockserver-client/mockserver-nodeother than the package or a documented module: both packages now have anexportsmap, so an unlisted path (.d.tsfiles,tasks/mockServer.js, etc.) now fails to resolve — resolve<package>/package.jsonand join a file'spath to that directory if you need one by location.
controlPlaneTLSMutualAuthenticationCAChainfor MockServer's certificate; add MockServer's own CA to that chain if it signs the server certificate.controlPlaneTLSMutualAuthenticationCAChain; add MockServer's own CA to the chain if it signs your client certificates (or use your own CA if it's the bundled default), and MockServer now refuses to start withmTLS required, no chain set, and the bundled default CA — set the chain or configure your own CA with
certificateAuthorityCertificate/certificateAuthorityPrivateKey.matchon its enums: every public enum is now#[non_exhaustive](add a wildcard arm), and server-sent enums (ResponseMode,BinaryUpstream,CrossProtocolTrigger, theLoad*enums) gain anUnknownvariant that cannot be sent back;LoadThresholdMetricalso gainsCheckFailureRate.never(),exactly,atMost,between,verifyZeroInteractions): the message now reads "found … but should have been found …" instead of "not found".statusCodeof0or outside 100–999 (most likely from a blank 8.0.0 dashboard status field): it is now rejected at creation with a400, or skipped with aWARN(naming it) when loaded from an initialization/persisted-expectations file, with the file backed up first.PUT /mockserver/asyncapi/verify, or the Java client'sverifyAsyncMessage): putatLeast/atMost/exactlyinsidecount, not at the top level — the endpoint now answers400for unknown fields instead of ignoring them.body).
operationIdnow count, instead of every recorded request (verifySequencewas unaffected).gen_ai.operation.name == "chat": Gemini calls are nowgenerate_content, and prompt-string completions (legacy/v1/completions, Mistral FIM, Ollama/api/generate, prompt-based Bedrock InvokeModel models) are nowtext_completion— update to matchchat,generate_contentandtext_completiontogether.retrieveRecordedRequests/retrieveRecordedRequestsById: now typedPromise<RequestDefinition[]>instead ofPromise<HttpResponse[]>; narrow each result toHttpRequestbefore reading HTTP-specific fields.matchBinaryExpectationsWhenProxying); set it tofalseto always forward as in 8.0.0.maxLoggedMatchFailuresproperty now defaults to50, so atINFOonly the first 50 "didn't match" entries per request are logged; setmaxLoggedMatchFailures=-1to keep logging every comparison.initializationJsonPathfile whoseids repeat: the file now keeps the last expectation for each repeatedid, not the first; remove the repeatedids, or put the one you want last.404/502: a response/forward template that fails, or whose output isn't valid, now answers500by default (templateFailureAsServerError); set it tofalseto keep the 8.0.0 answers.Also worth checking, though none is a breaking change: if you override the standard Docker images'
ENTRYPOINTor copy the jar out of them,/mockserver-netty-jar-with-dependencies.jaris now split into/mockserver.jarand/mockserver-deps.jar— use-cp /mockserver.jar:/mockserver-deps.jar:/libs/*(java -jar /mockserver.jarstill runs, but without the CDS start-up archive, so it starts more slowly); withforwardProxyBlockPrivateNetworkson, a request that matches no expectation and whoseHostheader names MockServer itself by a name it doesn't recognise as its own (a Docker Compose or Kubernetes service name, for example) now gets502 Bad Gatewayinstead of404 Not Found, because that name resolves to a private address — add the name tonoProxyHosts, or setattemptToProxyIfNoMatchingExpectation=falseif MockServer isn't used as a proxy, to get the404back; and if you setlocalBoundIP, it now also keeps the DNS and HTTP/3 ports on that address — a DNS query or HTTP/3 request sent to another address of the host is no longer answered, so send them to thelocalBoundIPaddress, or leavelocalBoundIPunset.Security
mockserver.velocityTemplateExecutionTimeout, default 5000 ms, same as JavaScript templates). A runaway#foreach, recursive macro or chained#defineblock could previously hold a template thread until restart; it now fails with a timeout error atits next loop iteration, macro call or
#parse/#evaluate. A single slow Java call inside a template is not interrupted, and the limit does not cap memory. Set the property to0to remove it.4.2.17.Finalto4.2.19.Final, and BouncyCastle from1.85to1.86, a security release whose advisories in the parts of Netty MockServer uses cover HTTP/1.1 request/response smuggling (including improper CRLF neutralization) and an origin validation error, unboundedresource consumption in the HTTP/1.1, HTTP/2, HTTP/3 and DNS codecs and the base codec, input misinterpretation in the SOCKS codec, and an SNI routing bypass and an improper access control in the handler module. Two visible changes: an HTTP/2 client whose
SETTINGS_INITIAL_WINDOW_SIZEchange wouldoverflow a stream's flow-control window now has its connection closed with
FLOW_CONTROL_ERROR, as RFC 9113 requires, instead of having that one stream reset; and in amultipart/form-datarequest, a file part whoseContent-Typeis not a plausible media type (for exampletext) is now read asapplication/octet-stream, so apartContentTypesmatcher for such a part must nameapplication/octet-stream. Netty 4.2.18 also tightened its HTTP/2 frame decoder to validate header values as well as names; unvalidated inbound frames (a leading space, an embedded DEL0x7F, other controlcharacters in a header value) are a shape MockServer is used to record, so inbound frame validation is now disabled on the multiplex codec, keeping that leniency for HTTP/2 requests on the multiplex path (this also disables inbound header-name validation there, since Netty folds both under one
flag); outbound names and HTTP/2-forbidden connection-specific headers (
Connection,Transfer-Encoding) remain validated.runBinaryand themockservercommand ran the bundle'smockserver.batundercmd.exe, so%NAME%in an argument or in the cache directory path was replaced with an environment variable's value, and a line break cutthe command short. On every platform they now run the bundle's own Java runtime directly, with the JVM options the launcher script applies, and pass each argument separately with no shell in between, so no shell can read
%,&,$or;in an argument or path as a variable or a command.MOCKSERVER_JAVA_OPTSis split on whitespace with quoted text kept together, so-Dx="a b"setsxtoa bon Linux and macOS too. Ashelloption passed inspawnOptionsis now ignored.start()ran themockserver.batlauncher withshell=True, socmd.execould treat characters in the launcher path or inextra_argsas commands rather than text. It now runscmd.exeitself withevery argument quoted, so characters such as
&,|and^reach MockServer unchanged.start()raisesValueErrorif the launcher path or anextra_argsentry contains a double quote, a line break or NUL, or if together they contain more than one%, whichcmd.exewould expand as anenvironment variable. Linux and macOS are unchanged and still use no shell.
cmd.exeon Windows.BinaryLauncher.startlet Ruby quote the arguments forcmd.exe, which follows different rules, so characters in the launcher path or inextra_argscould be read as commands. It now builds thecmd.execommand line itself and raisesMockServer::Errorif the launcher path or anextra_argsentry contains",<,>,|,&, a line break or NUL, or if together they contain more than one%. On Windows it needs a native Ruby (mswin or mingw, such as RubyInstaller). On Linux andmacOS it now never uses a shell, even with no arguments.
cmd.exeon Windows. They ranmockserver.batthroughcmd.exewith the standard argument quoting, whichcmd.exedoes not follow, so characters in the launcher path (fromMOCKSERVER_BINARY_CACHEor theuser's cache folder) could be read as commands. Each now builds the
cmd.execommand line itself, quoting every part, and refuses a launcher path that contains a double quote, a line break or NUL, or more than one%.cmd.exeon Windows.BinaryLauncher::start()let PHP quote the launcher path and$extraArgsforcmd.exe, which follows different rules, so characters in them could be read as commands. It now builds thecmd.execommand line itself and throws
BinaryInstallExceptionif the launcher path or an extra argument contains a double quote, a line break or NUL, or if together they contain more than one%.MOCKSERVER_BINARY_BASE_URLmade of repeated/no longer takes the Node launcher seconds to process.dompurifyresolves to 3.4.16 (DOM XSS viaIN_PLACEsanitize with anode-removing hook, Dependabot alert 593); dashboard npm
overridespinslodash-esto 4.18.1 (_.template/_.unset/_.omitadvisories; the affected functions are tree-shaken from the built dashboard anyway); the Node Testcontainers module's own development lockfile resolves newerundici,brace-expansionand@grpc/grpc-js(Dependabot alerts 581, 582, 584, 586, 591, 592 — the published package is unaffected, since it ships onlydist).zstdrequest or streamed compressed upstream response can no longer exhaust MockServer's memory. Azstdframe declares its decompressed size, and MockServer previously allocated that much up front (17 bytes claiming 1.5 GB threwOutOfMemoryErroron a 256 MB heap) — now decompressed in64 KB pieces, with
maxRequestBodySize/maxResponseBodySizeenforced as for any other coding.zstdstream, 8 KB on the wire, exhausted a 256 MB heap); such a stream is now capped atmaxResponseBodySize(50 MB by default) of data waiting to be written to the client, ending incomplete past that point rather than looking finished.network read is stopped; the wait doesn't count towards
streamIdleTimeoutSeconds(which now measures only an upstream that sends nothing while MockServer is reading it — a client that pauses keeps its stream, with at most the limit waiting for it, until it reads on, disconnects or takesnothing for
responseWriteStallTimeoutMillis).client goes away, MockServer now also closes the upstream, where before it kept reading an endless stream forever.
CONNECTtunnel is limited the same way, but bymaxRequestBodySize(10 MB by default) — the limit that tunnel already applied to a response it collected whole, notmaxResponseBodySize; through such a tunnel this backpressure is new for a streamed response, which beforewas queued in memory as fast as it arrived.
only by
maxInitialLineLengthand the trailers only bymaxHeaderSize, which were both unlimited by default, so MockServer kept buffering a line its client never ended, up to 2 GB or until its network memory ran out. MockServer now answers400and closes the connection once more than 8 KB ofone chunk-size line, or of the final
0line and its trailers counted together, is waiting to be read, on requests sent to it directly and through aCONNECTor SOCKS tunnel. The limit is fixed: real uploads use about 100 bytes per line, and 8 KB is what Tomcat allows. Anything within thelimit, the request line, headers and body sizes are unaffected, and a lower
maxInitialLineLengthormaxHeaderSizestill applies. HTTP/2 and HTTP/3 have no chunk-size lines.maxInitialLineLength(64 KB) andmaxHeaderSize(256 KB) were previously unlimited; set either to2147483647to remove the limit. A longerrequest line now gets
414, larger headers431, and any other unreadable request (an invalid header, a chunked body with an invalid chunk size)400, with the connection then closed — where before such a request was logged as anERRORand matched/answered from whatever had been read (a requestline over the limit, for example, as
GET /bad-request). This also applies throughCONNECT/SOCKS tunnels. A request is also now unreadable, and gets400, when the request before it on the same connection left bytes behind — for example a client that writes aGETbody with neitherContent-Lengthnor chunked encoding, as Node'shttp.requestdoes — where it used to get404forGET /bad-request. HTTP/2 and HTTP/3 now take their header limit frommaxHeaderSizetoo (see Changed); the limits apply only to requests MockServer receives — a mocked response with largerheaders is still sent intact.
Held network-read buffers are now copied once a request's retained pieces use less than half of the read they arrived in, cutting held memory 6× to over 2,000× in the cases measured.
over TLS, now use the same trust and client-certificate settings as the client's HTTP requests.
forwardProxyBlockPrivateNetworksnow also blocks carrier-grade NAT addresses (100.64.0.0/10). This shared address range (RFC 6598) is used by carrier-grade NAT and by overlay networks such as Tailscale to reach machines that are not on the public internet, so with the setting on a forwardor proxied request could still reach them. A target in that range, including written as an IPv4-mapped IPv6 address such as
::ffff:100.64.0.1, is now refused like a private-network address (with a502for HTTP); if you turn the setting on and forward to a Tailscale or other100.64.0.0/10address on purpose, leave the setting off to keep those forwards working.forwardProxyBlockPrivateNetworksnow also applies to the MCP tools that send requests to a URL you give them. With the setting enabled, 8.0.0 letrun_contract_test,run_resiliency_testandrun_mcp_contract_testsend requests to loopback, private-network and cloud-metadata addressesunchecked. Each tool now checks the URL's host before sending anything: a refused target is sent nothing, the tool returns an error naming the blocked address, and one warning is logged. Each request is checked again as it is sent, and with the setting enabled these tools no longer follow
redirects, which could lead to an address that was never checked. A spec path that does not start with
/is now always sent to the base URL's host.forwardProxyBlockPrivateNetworksnow checks the address MockServer actually connects to, and OpenAPI spec fetches. With the setting on, a forward, a proxied request, a webhook, a load scenario request, a drift alert or a WebSocket relay that MockServer connects to directly now goes to theexact address that passed the check, so a host name whose DNS answer changes between the check and the connection can no longer reach a blocked address. Every fetch of an OpenAPI spec from a URL (until now checked only for traffic validation), each remote
$refin a spec, and each redirectfollowed while fetching them are now checked too; a refused fetch makes the spec fail to load with a message naming the blocked address. Each MockServer applies its own setting to every spec it loads, so a server with the setting on in its own configuration checks them even when the global
property is off; a spec loaded by a server with the setting off is fetched again, with the check, by a server that has it on. To see those fetches MockServer wraps the JVM's default
ProxySelectorthe first time it loads a spec with the setting on; the wrapper stays for the life of theJVM, and a
ProxySelectoryour code sets at the same moment can be lost, so set your own before MockServer loads a spec. A forward refused because the address looked up to connect to is blocked is neither retried nor counted by the forward circuit breaker.forwardProxyBlockPrivateNetworksnow also applies to requests MockServer sends itself. With the setting enabled, 8.0.0 still sent these to loopback, private-network and cloud-metadata addresses unchecked: before-action, after-action and step webhooks, load scenario requests, and drift alertwebhooks. Each is now checked as a forward is, and a refused one is not sent and is logged once as a warning naming the blocked address. A refused blocking webhook with the
FAIL_FASTfailure policy makes the response a502 Bad Gateway(withBEST_EFFORTthe response goes ahead), a refusedload scenario request is counted as a failed request of kind
blocked(one warning for the run).proxyRemoteHostis checked although it is set in configuration, as it is for proxied requests; only the upstream proxies MockServer sends through (forwardHttpProxy,forwardHttpsProxy,forwardSocksProxy) are not checked.forwardProxyBlockPrivateNetworksnow applies to every forwarded and proxied request. With the setting enabled, 8.0.0 checked onlyhttpForwardactions. Overridden forwarded requests (forwardOverriddenRequest), class and object forward callbacks, binary forwarding, and requests thatmatched no expectation and were proxied on did not apply the check, so an expectation, or an unmatched proxied request, could reach loopback, private-network and cloud-metadata addresses. All of them now apply it, as forward actions do: an HTTP request gets
502 Bad Gateway, a binaryconnection is closed, and a warning names the blocked address. A request sent through
forwardHttpProxyalso has its Host header checked, as that proxy is sent it as the address to go to. With the setting enabled, a request that matches no expectation and whose Host header names MockServeritself by a name it does not recognise as its own (a Docker Compose or Kubernetes service name, for example) now gets
502 Bad Gatewayand a warning instead of404 Not Found, because that name resolves to a private address — see Upgrading from 8.0.0.PUT /mockserver/configurationnow take effect for every way of starting MockServer, and all at once. A server started without a configuration object (command line, Docker, Maven plugin) previously held two copies of its configuration, so aPUTthat reportedsuccess (including enabling control-plane authentication, or lowering
maxLogEntries/maxEventLogSizeInBytes, or enablingredactSecretsInLog) left request handling on the old, insecure or unenforced values; settings given at startup, and servers started throughClientAndServer, the JUnitintegrations or Spring, were not affected. A
PUTthat changes authentication or TLS settings is now also applied atomically: control-plane authentication/authorization and the server TLS settings (tlsMutualAuthenticationRequiredand its certificate chain) switch from all-old to all-new withnothing in between — closing a sub-millisecond window where a
PUTswitching from mTLS to JWT/OIDC could briefly require no authentication at all, or a TLS connection opened mid-change could keep using the old setup. A rejectedPUT(an invalid certificate path, a negativeglobalResponseDelayMillis) now answers400having changed nothing, where fields ahead of the invalid one used to stay applied. An MCP tool call is now also authorized with the settings it was authenticated with, rather than possibly a laterPUT's. Outbound TLS connections now cache their TLSsetup only under the exact settings it was built from, so a
PUTchangingforwardProxyTLSX509CertificatesTrustManagerTypemid-build can no longer leave a stale trust-all setup cached under the old settings; turninghttp2Enabledoff at runtime now also stops outbound TLS connections offeringHTTP/2.
redactSecretsInLognow masks credentials everywhere the event log is shown or retrieved, including the console/retrieved curl rendering of a proxied or forwarded request, JSON logmessage/arguments/expectationfields, the separate cookie list, HAR andformat=CURLexports, match-failureexplanations, error log entries, failed response verifications, and — newly — the bytes of a binary (non-HTTP) message in a "matched"/"didn't match" log entry (shown as
***REDACTED***, where the "received binary request" message already masked them);redactSecretsInRecordedExpectationsnow alsomasks cookie values. Masking now applies even to entries recorded before the setting was switched on, since redaction happens when an entry is shown or retrieved, not when it's written; what's not retroactively fixed is anything captured by MockServer before this release — treat logs, exports
and recordings captured pre-upgrade as still containing those values in full.
/mockserver/generateExpectationand LLM drift analysis now redact credentials from the prompt sent to an external LLM backend, unconditionally — sensitive headers, credential-shaped query parameters and JSON fields, OAuth codes, JWT-shaped tokens, and embedded URL credentials are replaced with***REDACTED***before the prompt leaves MockServer, independent ofredactSecretsInLog. The same unconditional redaction covers the newnarrationfield onPUT /mockserver/explain/explainUnmatched(see Added): credential values are masked whether or notredactSecretsInLogis on. Theexplain_request,explainUnmatchedand other MCP/REST diagnostic output, by contrast, is redacted the same way the event log is — i.e. only whenredactSecretsInLogis enabled — exceptdiagnose_config, which always masks credential values. Treat any credentials sent throughgenerateExpectation/drift analysis with a backend configured as previously exposed to that LLM service.Added
PUT /mockserver/explain?correlationId=<id>. Give it the correlation ID of a recorded request (fromPUT /mockserver/retrieve?type=LOGS&format=LOG_ENTRIESor the dashboard) and MockServer checks thatrequest again against your current expectations, in the order it evaluates them. The answer names the expectation that would serve the request now, gives a reason for every expectation checked before it (different fields; another namespace; used up or expired; waiting for another scenario
state; served only a percentage of the time; LLM conversation mismatch; a
not(...)request matcher that excludes the request), lists lower-priority expectations that also match but are never reached, and reports how the request was handled when it arrived, including, when MockServer forwardedthe request and the forward failed with a 502, the expectation that forwarded it (or that it was proxied without one) and the reason the forward failed. At most 500 expectations are checked per call. The route has no bare
/explainalias, so a mock of your own onPUT /explainkeeps working.In the dashboard, every group of log messages for a request has an Explain button that shows the same answer, and the Java client has a typed
explain(correlationId)method returning aRequestExplanation.explain_requesttakes the correlation ID of a request MockServer has received and returns the same answer asPUT /mockserver/explain. An unknownor evicted correlation ID comes back as a tool error.
diagnose_configlists the configuration settings changed from their default, with the value and where each came from (system property, properties file, environment variable or runtime setter), or looks up one setting by name in any form(
maxExpectations,mockserver.maxExpectations,MOCKSERVER_MAX_EXPECTATIONSormax-expectations), showing a setting at its default with the default's value, and suggests the setting you probably meant when nothing matches. It also lists eachmockserver.*/MOCKSERVER_*key you setthat MockServer does not recognise, with the setting it was probably meant to be (by name only, never its value). Both are read-only, so a principal with only the READ role can call them when control-plane authorization is on. Their output is redacted:
diagnose_configalways maskscredentials, and
explain_requestmasks credentials quoted from your traffic whenredactSecretsInLogis enabled, as the event log does.explain,debugMismatchandexplainUnmatchedcalls (explain,debug_mismatchandexplain_unmatchedin Python, Ruby andRust;
Explain,DebugMismatchandExplainUnmatchedin Go and .NET, which also hasAsyncversions), joining the Java client's typedexplain.explaintakes thecorrelation ID of a recorded request and returns which expectation would serve it now, why each expectation checked before it was passed over, which lower-priority ones it hides, and how the request was handled when it arrived;
debugMismatchcompares a request you describe with every activeexpectation, field by field;
explainUnmatchedlists the closest expectations for recent unmatched requests, optionally with a suggested JSON patch for each. An unknown or evicted correlation ID fails with the server's reason.matcher before and after; Apply Fix updates the expectation only when you select it, and refuses if anything it would change was edited in the meantime. Over REST, add
"suggestFixes": truetoPUT /mockserver/explainUnmatchedto get each suggestion as a standard JSON Patch. Values thelog redacts, and bodies the log kept only part of, are never copied into a fix.
PUT /mockserver/lintchecks your active expectations, or the expectations you send in the body without storing them, andmockserver lint expectations.jsonchecks files with no server running. It reports anexpectation that another one evaluated earlier always matches first (shadowed),
times,timeToLiveorpercentageof 0, a path without a leading/, a misspelt method or header name, and STRICT JSON matching of a body with arrays, among other checks. Creating expectations withPUT /mockserver/expectationnow runs the quick per-expectation checks too: the expectations are still stored, and any problems are counted in anx-mockserver-lint-warningsresponse header and logged as aWARN. Expectations loaded from aninitializationJsonPathfile are checked too, eachtime the file loads. Lint is advisory and never rejects an expectation. In the dashboard, a Lint button on the Active Expectations panel lists the findings with their severity, rule and message.
explain_forward_failure,suggest_expectation_fix(the same guarded JSON Patch asexplainUnmatched's"suggestFixes": true),lint_expectations(returning at mostmaxIssuesissues, default 100), andtest_template. The first three are read-only, so a principal with only the READ role can call them when control-plane authorization is on;test_templateruns thetemplate code it is sent, so, like its REST endpoint, it needs the mutate role. Output is redacted as the event log is when
redactSecretsInLogis enabled, and a forward failure's reason is cut at 2,048 characters.PUT /mockserver/template/test. Send a Velocity, Mustache or JavaScript template and an optional sample request, and MockServer renders it with the same engines, security settings and time limits it uses when serving. Itreturns the rendered response (or the request, for a forward template), or the reason it failed with the line and column in your template. Output that is not a valid response comes back with what is wrong with it and the raw text; serving it would answer with a 500 (a 404, or a 502 for a
forward template, with
templateFailureAsServerError=false). Warnings point to each Velocity reference that did not resolve, to each Mustache variable that did not resolve and so rendered as empty text, and to eachscenario.set(...)call, which a dry run reports rather than applies; a dryrun never changes scenario state or appears in the event log. A JavaScript or
Velocity template is always stopped after its time limit, even when that limit is 0 (then after 5 seconds); a Mustache template, or a Velocity template busy inside one long Java call, cannot be stopped, so the dry run answers once the limit plus 5 seconds has passed; at most two dry runs run
at once, and a third gets a 429. When control-plane authorisation is on, a dry run needs the mutate role. The route has no bare
/template/testalias, so a mock of your own on that path keeps working.at template line 2, column 29, counted from yourtemplate's first line, and a hint when the cause is an undefined variable, a field read from a missing value, or an unclosed bracket or quote. Velocity and Mustache errors already gave the line, and are unchanged.
PUT /mockserver/explainandPUT /mockserver/explainUnmatchedcan add a plain-language summary from your own LLM. When the newllmExplainNarrationEnabledproperty is on (defaultfalse), a runtime LLM backend is configured (llmProvider, or a provider API-key environment variable)and the caller adds
?narrate=true, the response gains anarrationfield, labelled as AI-generated, beside the unchanged deterministic explanation. A backend configured for other features is not enough on its own, and nothing is sent while a request is being served. Credential values fromthe request and your expectations are replaced with
***REDACTED***before the explanation leaves MockServer, whether or notredactSecretsInLogis on. The call runs off the request thread and is bounded byllmRequestTimeoutMillisplus two seconds. When narration is turned off, no backendis configured, the LLM fails or times out, or two summaries are already running,
narrationsays why it is unavailable instead of returning an error.why_did_verify_fail,fix_my_expectationandwhy_forward_failedtell your own assistant which MockServer tools to call, in which order, and what each result means; MockServer still calls no languagemodel for these three.
fix_my_expectationchanges an expectation only after you agree, and replaces it in place, starting from the fix MockServer suggests withsuggest_expectation_fix;why_forward_failedstarts from the reasonexplain_forward_failurereports, falling back to comparingfields or reading the logs only when MockServer has no fix, cannot name the cause or recorded no failed forward.
binaryMessageFraming(defaultRAW, unchanged) now also takesMYSQL,REDIS,POSTGRESQLandLENGTH_PREFIX(the last configuredvia
binaryMessageLengthPrefixBytes(1, 2, 4 or 8, default 4),binaryMessageLengthPrefixByteOrder(defaultBIG_ENDIAN),binaryMessageLengthPrefixOffset(bytes before the field, default 0) andbinaryMessageLengthIncludesPrefix(whether the length counts the whole message, defaultfalse), which fits protocols such as Thrift's framed transport, MongoDB's wire protocol and DNS over TCP. As withPOSTGRESQL, a message may be at mostmaxRequestBodySizebytes, a connection that declares a longer one or sends bytes the framing does not allow is closed, and an unrecognisedvalue set as a property is logged once and read as the default. To proxy MySQL, whose server speaks first, also set
forwardBinaryServerFirstWaitMillison a connection with a forward target (port forwarding, transparent proxy or PROXY protocol); mocking MySQL with no upstream server is notpossible, as MockServer cannot send the server's greeting. A TLS handshake on a MySQL connection is recognised only straight after an
SSLRequest.upstreamfield (Java:binaryResponse(bytes).withUpstream(BinaryResponse.Upstream....)):ANSWER_ONLY(the default, unchanged)answers and does not forward;
ANSWER_AND_FORWARDanswers, forwards themessage so the real server still sees it, and drops the server's reply;
FORWARD_AND_REPLACEforwards the message and writes the binary response in place of the server's reply once that reply has ended (with adelay, the server's later replies wait behind it, so the client gets them inorder). Both need
matchBinaryExpectationsWhenProxying(on by default) andbinaryMessageFramingset toPOSTGRESQL, which tells MockServer where a reply ends; without that framing the expectation answers asANSWER_ONLYand one warning is logged per connection. The field is in the JSON schema,the OpenAPI spec and every client library.
forwardBinaryServerFirstWaitMillis. Set it (for example to250) and a port-forwarded, transparently proxied or PROXY-protocol connection whose client sends nothing for that long istaken as binary: MockServer opens its upstream connection and relays the greeting, and the rest of the session. It is off (
0) by default, because a client that opens a connection and sends HTTP only after the wait would then be relayed to the upstream rather than matched against yourexpectations.
binaryProxyListenercan be told what the upstream server sends unprompted: the newonUpstreamMessagemethod is called for every read from the upstream server that is not a message's response — bytes it sent unprompted, and the rest of a response that arrived in more than one read. Itis a default method that does nothing, so existing listeners, lambdas included, are unaffected and are not called for these reads. A listener that overrides it and falls more than 64 calls behind slows the upstream server down, except while a message is waiting for its response.
matchBinaryExpectationsWhenProxying(on by default; setfalseto always forward) lets a binary expectation answer some messages on an otherwise-proxied connection relayed on one upstream connection, matched only when its bytes equal the expectation's exactly, so a test can use a real server for mostof a session and fake one part of it, such as a canned result for one PostgreSQL query. The upstream never sees an answered message, so the canned reply must suit the session's real state.
--print-configends the setting's line with(default: ...),GET /mockserver/configand the MCPdiagnose_configtool add adefaultfield, and the dashboard's Server Info tab shows the default besidethe value. A default worked out from the JVM heap size, such as
maxExpectations, shows the value worked out now. A credential's default is always shown as***REDACTED***, anddefaultis left out when MockServer cannot work it out.--print-config,GET /mockserver/configand the dashboard's Server Info tab also now list the configuration MockServer ignored: after the properties in effect they list each unrecognisedmockserver.*/MOCKSERVER_*key with its suggested correction (name only, never the value it was setto), and
GET /mockserver/config?nonDefault=truelists only the properties not at their built-in default, which is everything you have changed. A property at its built-in default now shows that default's value instead of(default); a default worked out from another property, such asringBufferSize, shows the value worked out now. Credentials are still shown only as***REDACTED***, including at their default./mockserver/metrics: four for the in-flight ring (mock_server_event_log_ring_occupancy,_ring_capacity,_in_flight_bytes,_max_in_flight_bytes) and four for the retained deque (mock_server_event_log_retained_entries,_retained_bytes,_max_retained_entries,_max_retained_bytes).mock_server_expectations_bytesreports live memory held by the store;mock_server_max_expectations_bytesthe byte budget in force (0whenmaxExpectationsSizeInBytesis off);mock_server_expectations_byte_evicted_totalcounts byte-drivenevictions.
mock_server_accept_queue_backlog_configuredreports the configured accept-queue depth; on Linux,mock_server_accept_queue_backlog_effectivereports the kernel-capped value.jvm_runtime_info(gauge, always 1, reports the running JVM/GC in labels),jvm_memory_allocated_bytes(a monotonic gauge of cumulative bytes allocated across all threads),jvm_buffer_pool_used_bytes/jvm_buffer_pool_used_buffers(NIO buffer pools), andnetty_direct_memory_used_bytes(Netty's own direct-memory tracking).mock_server_request_read_to_decode_duration_seconds(from MockServer reading the first bytes of a request to it having decoded the headers) andmock_server_request_transport_duration_seconds(from reading a request's headers to the last byte of its response beingwritten, including delays — unlike the existing
mock_server_request_duration_seconds, which stops when a response is handed off for writing).mock_server_inbound_connections_open,mock_server_inbound_connections_rejected_totalandmock_server_inbound_connections_idle_closed_total(seemaxInboundConnectionsbelow).mock_server_scheduler_queued_tasksandmock_server_template_action_queued_tasksshow the depth of the action and template-render queues, which are deliberately not limited because their work must not be dropped.maxExpectationsSizeInBytes(default 0 = off) caps stored-expectation memory by byte budget alongside the existingmaxExpectationscount.maxPendingDelayedResponsesandmaxQueuedTemplateActions(both sized from heap, capped at 100,000, or 1,000 when the JVM reports no heap limit;0restores the old unbounded behaviour) bound requests waiting on a delay or a template thread, answering503 Service UnavailablewithRetry-After: 1past the limit instead of growing memory without bound (a refused request still counts as a match; delayed side actions are dropped, not refused, once their own equal-sized budget is full; a forwarded response skips its chaos latency rather than being refused); delayed WebSocket replies get thesame budget, closing the WebSocket with status
1013(Try Again Later) once full, and reads pause at 128 waiting replies per connection (a fixed constant, no setting) so a fast-sending client is slowed by TCP flow control instead of growing memory; reply frames are now sent strictly in delay order.maxInboundConnections(default 0 = no limit) caps open client connections: a connection beyond the limit is reset at once instead of being accepted, a warning is logged at most every 10 seconds, and new connections are accepted again as soon as one closes. A CONNECT/SOCKS tunnel to MockServeritself uses two slots, and if its second is refused the client now gets a
502instead of waiting forever.mockserver.soBacklog(default 1024, previously hard-coded) makes the TCP accept-queue depth configurable; the effective depth is still capped by the kernel (net.core.somaxconnonLinux,
kern.ipc.somaxconnon macOS).-jar-with-dependencies-linux-x86_64.jarand-jar-with-dependencies-linux-aarch_64.jarare ~13 MB smaller by carrying only their own architecture's natives.mockserver/mockserver:<version>-http3(alsomockserver-<version>-http3,latest-http3, andsnapshot-http3/mockserver-snapshot-http3formasterbuilds; Helmimage.variant=http3) is the standard image plus the QUIC native, needed to actually serve HTTP/3 (see Upgrading from 8.0.0).?logLimit=N(up to 500, default 100) for more log/request rows per update. TheBreakpoints form gains Min status/Max status fields and a
status:scope-box syntax, limited to the Response phase.500-by-default entry underChanged for the response shape and migration).
previous_response_id/GET /v1/responses/{id}(maxOpenAiResponsesSizeInBytes, default a twentieth of the heap;0limits by count only).forwardProxyBlockPrivateNetworksto becometrue,localBoundIPto become127.0.0.1,attemptToProxyIfNoMatchingExpectationto becomefalse, and the HTTP parsing limitsmaxInitialLineLength/maxHeaderSize/maxChunkSizeto become 8192/16384/16384 bytes), once per JVM; setting the property yourself silences its warning, so you can choose now and not be surprised when the defaults change. No default changes in this release. Misspeltmockserver.*/MOCKSERVER_*properties now get a "did you mean" suggestion at startup, in theform you used (
MOCKSERVER_METRICS_ENABLEsuggestsMOCKSERVER_METRICS_ENABLED,mockserver.max_expectationssuggestsmockserver.maxExpectations), naming the property only, never the value (see the--print-config/GET /mockserver/configsub-bullet above for where else ignored keys anddefaults are listed).
detailedVerificationFailures, default on): the expected vs. actual count, the closest non-matching requests/responses with their differing fields, and — for a sequence — which step failed. The block isappended, so code that checks the start of the message is unaffected; set
detailedVerificationFailures=falseto drop it.ConditionalRequestDefinition(if_request,then_request,else_request,not_condition); Goadds
If/Then/ElsetoHttpRequestwithConditionalRequest(...); .NET addsIf/Then/ElsewithHttpRequest.RequestIf(...); Rust and PHP addHttpRequest::conditional(...); the .NET, Rust and PHP request matchers also gain the OpenAPI fields (specUrlOrPayload,operationId,contextPathPrefix) a branch can use. The same five clients' load-scenario steps now take per-step checks (LoadCheck:source,headerName,jsonPath,comparator,value, named in each language's style) and acheckslist; Go, .NET and Rust also gain a typedCHECK_FAILURE_RATEthreshold metric, and Rust's
LoadStepgainsname(...)/label(key, value)andLoadScenariogainslabel(key, value)(see the "Every client can now ask why a request matched" sub-bullet above for theexplain/debugMismatch/explainUnmatchedparity).performance.htmlshowinghealthy/peak request rate, latency and request-history retention from 1 core/512 MB up to 6 cores/2 GB, driven by four load generators per size so the test measures MockServer rather than the generator.
MockServer.getDnsPort()and the start-up log: alsoClientAndServer.getDnsPort()(including on theClientAndServerthe JUnit 5 extension injects),MockServerRule.getDnsPort(), the Spring listener's${mockServerDnsPort}placeholder and@MockServerDnsPortannotation, and thednsPortfield ofPUT /mockserver/status's answer (each gives-1, or the field is left out, while DNS mocking is off).@MockServerTestnow also acceptsmockserver.dnsEnabledandmockserver.dnsPort.Changed
forwardBinaryRequestsWithoutWaitingForResponsewith it, are removed. The upstream now sees one connection per client connection, held openas long as the client's is: everything it sends reaches the client, closing its connection closes the client's too, and a clien
Configuration
📅 Schedule: (UTC)
🚦 Automerge: Enabled.
♻ Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.