1.41.0 (Pending)
Incompatible behavior changes
Changes that are expected to cause an incompatibility if applicable; deployment changes are likely required
dynamic_forward_proxy: The dynamic forward proxy cluster now replaces a host with a new host instance when DNS re-resolution changes its address, publishing the change as a regular cluster membership update (old host removed, new host added). Connection pools bound to the old address are therefore drained, instead of existing connections continuing to use the stale address indefinitely. This change can be reverted by setting the runtime guard
envoy.reloadable_features.dfp_cluster_replace_host_on_address_changetofalse, which restores the previous behavior of mutating the existing host’s address in place.geoip: The HTTP geoip filter now removes every configured geolocation header from the incoming request before the lookup, so a header a client sent is never forwarded upstream as if the lookup had set it. Previously a client-supplied header was kept whenever the lookup had no value for it: an address absent from the database, a database error, a field the database lacks for that address, or a request whose lookup was skipped because the downstream address was not an IP address. Geolocation providers report the headers they are configured to write through the new
Driver::geoHeaderNames()method, which defaults to empty for providers that do not implement it. This behavior can be reverted by setting the runtime guardenvoy.reloadable_features.geoip_sanitize_geo_headerstofalse.stats: The tag-extracted names of per-worker stats now keep
workeras a separate name segment when theworker_idtag is extracted:server.worker_1.watchdog_missis now extracted toserver.worker.watchdog_missinstead ofserver.worker_watchdog_miss, and the same applies to the per-worker stats underlistener.<address>.,listener_manager.andthread_local_cluster_manager.. Prometheus names are unchanged, because.and_are both sanitized to_there. Metric names change only for sinks that emit the tag-extracted name verbatim, such asdog_statsd,metrics_serviceand the OpenTelemetry sink.
Minor behavior changes
Changes that may cause incompatibilities for some users, but should not for most
config: xDS resource types that may be subscribed to while a config update is being applied are now paused centrally for every subscription, regardless of its transport (gRPC, REST or filesystem), instead of by each xDS API. As part of this change, Virtual Host Discovery Service (VHDS) requests are now also paused while a Route Discovery Service (RDS) update is being applied, so that the VHDS subscriptions created by the update are batched into a single request.
contrib: The Istio peer metadata conversion now takes a peer’s app name and version from the
appandversionlabels again, and usesapp.kubernetes.io/nameandapp.kubernetes.io/versiononly when those labels are absent or empty. A workload’s own stats always useappandversion, so giving theapp.kubernetes.io/*labels precedence madesource_app,destination_app,source_versionanddestination_versionreported by a peer differ from the values the workload reports for itself, and the same workload showed up under two names. This restores the label precedence Istio proxies used beforeapp.kubernetes.io/*labels were preferred.mcp: Removed the 10MB (10485760 bytes) upper bound on the MCP filter’s max_request_body_size and the per-route max_request_body_size. Any
uint32value is now accepted; the 8KB default is unchanged.on_demand: On-demand cluster discovery (ODCDS) can now answer repeated requests for a cluster the server has already reported as missing immediately from that remembered answer, instead of starting another discovery and waiting for the response or the discovery timeout. The answer is remembered per config source, only for explicitly requested clusters, and is withdrawn as soon as an update delivers the cluster. Requests answered this way are counted in the new cluster_manager.odcds.known_missing_answers counter. This behavior is off by default and can be enabled by setting the runtime guard
envoy.reloadable_features.odcds_missing_cluster_cachetotrue.stats: Added the new
envoy.upstream_from_zoneandenvoy.upstream_to_zonetags, extracted by the default stats tag-extraction rules from a cluster’s upstream per-zone stats (cluster.<name>.zone.<from_zone>.<to_zone>.*). Flat stat names are unchanged.
Bug fixes
Changes expected to improve the state of the world and are unlikely to have negative effects
dynamic_modules: Fixed dynamic module metric IDs. The first metric defined with labels got the same ID as the first one defined without labels, and metrics of different types also shared IDs. A module that recorded a metric with the wrong number of label values, or through the call of another metric type, then changed a different metric instead of getting an error. Every metric now has its own ID.
mcp_json_rest_bridge: Fixed MCP header Base64 decoding so values with an incomplete Base64 wrapper are treated as literals, and an empty Base64 payload correctly decodes to an empty string.
mcp_json_rest_bridge: Fixed the
mcp_json_rest_bridgeHTTP filter per-route configuration validation to reject duplicate(host, path)endpoint configurations instead of silently merging tools and ignoring subsequenttool_list_http_ruleortool_list_localsettings.mcp_json_rest_bridge: Fixed the
mcp_json_rest_bridgeHTTP filter to respond with HTTP404 Not Foundinstead of200 OKwhen a stateless MCP2026-07-28request uses a method that the bridge does not implement, as required by the Streamable HTTP transport. The JSON-RPC error code is unchanged (-32601). This also applies to the legacyinitializeandnotifications/initializedmethods sent as stateless requests. Requests that use MCP2025-11-25or earlier still receive200 OK.overload_manager: Fixed a use-after-free that could crash a worker thread during Envoy shutdown when a TCP listener is configured with exact_balance and the
envoy.resource_monitors.global_downstream_max_connectionsoverload manager resource monitor is configured. A connection accepted on one worker could be handed off to a different worker via connection balancing while still holding a reference into the originating worker’s thread-local overload state; because worker threads shut down independently with no ordering guarantee relative to one another, the destination worker could destroy the connection after the originating worker had already torn down its own thread-local state, dereferencing freed memory. The connection’s overload state reference is now rebound to the receiving worker’s own thread-local state once the connection has settled on its final worker, so it is always valid for as long as the connection itself is.udp: Fixed a hot restart child reading packets from an inherited UDP socket while its listener was still paused. The QUIC listener injects a read event on its listener to process the handshakes it buffered from packets the parent forwarded, and the listener then read the socket the parent was still serving, so the packets of the parent’s connections were dequeued by the child and answered with stateless resets until the clients had reconnected. A paused listener now runs its read-ready callback on such an event without reading the socket.
upstream: Fixed a crash (SIGSEGV) in load stats reporting and health discovery responses when EDS removed the last host from a locality after active health checking failed. Both reporting paths now skip empty locality groups.
Removed config or runtime
Normally occurs at the end of the deprecation period
config: Removed runtime flag
envoy.reloadable_features.xds_legacy_delta_skip_subsequent_nodeand legacy code paths.http: Removed runtime flag
envoy.reloadable_features.http1_close_connection_on_zombie_stream_completeand legacy code paths.mcp: Removed the runtime guard
envoy.reloadable_features.mcp_filter_use_new_metadata_namespaceand the legacy code path it guarded. The MCP filter always publishes its dynamic metadata under theenvoy.filters.http.mcpnamespace (and the MCP router reads it from there); the legacymcp_proxynamespace is no longer available.
New features
access_log: Added the
%DOWNSTREAM_PEER_CERT_CHAIN%substitution formatter which returns the full downstream peer certificate chain in URL-encoded PEM format.ai_protocol_manager: Added external_buffer_config to the AI Protocol Manager filter (alpha), making the store that offloaded payloads are written to a pluggable
envoy.ai_protocol_manager.external_bufferextension. When unset, envoy.ai_protocol_manager.external_buffer.in_memory is used; it holds the payload in memory and does not bound its size.config: YAML configuration now honors the explicit
!!floattag: a scalar such as!!float 5000.0is loaded as a JSON number instead of a string, so it stays a number inside agoogle.protobuf.Struct(e.g. atyped_configpacked as aStruct). Untagged float literals are unchanged and still load as strings. Non-finite values are loaded as the stringsInfinity,-InfinityandNaN. A!!floatscalar that cannot be decoded as a double now fails configuration loading. See special YAML usage.ext_proc: Added max_streamed_body_chunk_size and per-route max_streamed_body_chunk_size to limit the body payload size of individual
ProcessingRequestmessages sent inSTREAMEDandFULL_DUPLEX_STREAMEDbody processing modes.http2: Added the
metadata_droppedHTTP/2 codec stat. It counts outbound metadata that is dropped becauseallow_metadataisn’t enabled on the connection.matching: Added the URI template input matcher, which matches a path against a URI template with the same semantics as route path_match_policy.
mcp_json_rest_bridge: Added validation of
Mcp-Param-{name}request headers for MCP2026-07-28tools/call requests, configured per tool with the new mcp_param_headers field. Each mapping names the header, the literal property path of the argument, and itsSTRING,INTEGERorBOOLEANtype. A missing, unexpected, malformed, or mismatched header is rejected with aHeaderMismatcherror.overload_manager: Added the new HTTP priority load shed filter envoy.filters.http.priority_load_shed, which maps request header integer ranges to overload manager load shed points. It supports fallback shedding via a default load shed point.
upstream: Added
cluster_manager.odcds.discovery_attempt,cluster_manager.odcds.discovery_success,cluster_manager.odcds.discovery_missing, andcluster_manager.odcds.discovery_timeoutcounters for on-demand cluster discovery. Each counter increments once per discovery, regardless of how many requests were waiting for that cluster.watchdog: Added log_level to the
envoy.watchdog.backtrace_actionwatchdog action to make the level of the emitted backtrace logs configurable. The level defaults to critical.