.. _version_history_1.41.0: 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_change`` to ``false``, which restores the previous behavior of mutating the existing host's address in place. * **geoip**: The :ref:`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 guard ``envoy.reloadable_features.geoip_sanitize_geo_headers`` to ``false``. * **stats**: The tag-extracted names of per-worker stats now keep ``worker`` as a separate name segment when the ``worker_id`` tag is extracted: ``server.worker_1.watchdog_miss`` is now extracted to ``server.worker.watchdog_miss`` instead of ``server.worker_watchdog_miss``, and the same applies to the per-worker stats under ``listener.
.``, ``listener_manager.`` and ``thread_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 as ``dog_statsd``, ``metrics_service`` and 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 ``app`` and ``version`` labels again, and uses ``app.kubernetes.io/name`` and ``app.kubernetes.io/version`` only when those labels are absent or empty. A workload's own stats always use ``app`` and ``version``, so giving the ``app.kubernetes.io/*`` labels precedence made ``source_app``, ``destination_app``, ``source_version`` and ``destination_version`` reported 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 before ``app.kubernetes.io/*`` labels were preferred. * **mcp**: Removed the 10MB (10485760 bytes) upper bound on the MCP filter's :ref:`max_request_body_size ` and the per-route :ref:`max_request_body_size `. Any ``uint32`` value 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 :ref:`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_cache`` to ``true``. * **stats**: Added the new ``envoy.upstream_from_zone`` and ``envoy.upstream_to_zone`` tags, extracted by the default stats tag-extraction rules from a cluster's upstream per-zone stats (``cluster..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_bridge`` HTTP filter per-route configuration validation to reject duplicate ``(host, path)`` endpoint configurations instead of silently merging tools and ignoring subsequent ``tool_list_http_rule`` or ``tool_list_local`` settings. * **mcp_json_rest_bridge**: Fixed the ``mcp_json_rest_bridge`` HTTP filter to respond with HTTP ``404 Not Found`` instead of ``200 OK`` when a stateless MCP ``2026-07-28`` request 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 legacy ``initialize`` and ``notifications/initialized`` methods sent as stateless requests. Requests that use MCP ``2025-11-25`` or earlier still receive ``200 OK``. * **overload_manager**: Fixed a use-after-free that could crash a worker thread during Envoy shutdown when a TCP listener is configured with :ref:`exact_balance ` and the ``envoy.resource_monitors.global_downstream_max_connections`` overload 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* :ref:`deprecation period ` * **config**: Removed runtime flag ``envoy.reloadable_features.xds_legacy_delta_skip_subsequent_node`` and legacy code paths. * **http**: Removed runtime flag ``envoy.reloadable_features.http1_close_connection_on_zombie_stream_complete`` and legacy code paths. * **mcp**: Removed the runtime guard ``envoy.reloadable_features.mcp_filter_use_new_metadata_namespace`` and the legacy code path it guarded. The MCP filter always publishes its dynamic metadata under the ``envoy.filters.http.mcp`` namespace (and the MCP router reads it from there); the legacy ``mcp_proxy`` namespace is no longer available. New features ------------ * **access_log**: Added the ``%DOWNSTREAM_PEER_CERT_CHAIN%`` :ref:`substitution formatter` which returns the full downstream peer certificate chain in URL-encoded PEM format. * **ai_protocol_manager**: Added :ref:`external_buffer_config ` to the :ref:`AI Protocol Manager filter ` (alpha), making the store that offloaded payloads are written to a pluggable ``envoy.ai_protocol_manager.external_buffer`` extension. When unset, :ref:`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 ``!!float`` tag: a scalar such as ``!!float 5000.0`` is loaded as a JSON number instead of a string, so it stays a number inside a ``google.protobuf.Struct`` (e.g. a ``typed_config`` packed as a ``Struct``). Untagged float literals are unchanged and still load as strings. Non-finite values are loaded as the strings ``Infinity``, ``-Infinity`` and ``NaN``. A ``!!float`` scalar that cannot be decoded as a double now fails configuration loading. See :ref:`special YAML usage `. * **ext_proc**: Added :ref:`max_streamed_body_chunk_size ` and per-route :ref:`max_streamed_body_chunk_size ` to limit the body payload size of individual ``ProcessingRequest`` messages sent in ``STREAMED`` and ``FULL_DUPLEX_STREAMED`` body processing modes. * **http2**: Added the ``metadata_dropped`` HTTP/2 :ref:`codec stat `. It counts outbound metadata that is dropped because ``allow_metadata`` isn't enabled on the connection. * **matching**: Added the :ref:`URI template input matcher `, which matches a path against a URI template with the same semantics as route :ref:`path_match_policy `. * **mcp_json_rest_bridge**: Added validation of ``Mcp-Param-{name}`` request headers for MCP ``2026-07-28`` tools/call requests, configured per tool with the new :ref:`mcp_param_headers ` field. Each mapping names the header, the literal property path of the argument, and its ``STRING``, ``INTEGER`` or ``BOOLEAN`` type. A missing, unexpected, malformed, or mismatched header is rejected with a ``HeaderMismatch`` error. * **overload_manager**: Added the new HTTP priority load shed filter :ref:`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``, and ``cluster_manager.odcds.discovery_timeout`` counters for :ref:`on-demand cluster discovery `. Each counter increments once per discovery, regardless of how many requests were waiting for that cluster. * **watchdog**: Added :ref:`log_level ` to the ``envoy.watchdog.backtrace_action`` watchdog action to make the level of the emitted backtrace logs configurable. The level defaults to critical.