Repository: envoyproxy/gateway
Pull request #5332 (2025-02-23 00:06:16)

chore: cleanup after adding RequestID
**What type of PR is this?**
<!--
Your PR title should be descriptive, and generally start with type that contains a subsystem name with `()` if necessary
and summary followed by a colon. format `chore/docs/api/feat/fix/refactor/style/test: summary`.
Examples:
* "docs: fix grammar error"
* "feat(translator): add new feature"
* "fix: fix xx bug"
* "chore: change ci & build tools etc"
* "api: add xxx fields in ClientTrafficPolicy"
-->

<!--
NOTE: If your PR contains any API changes (changes under `/api`), we recommend you to separate these API changes into
a new PR, and we will review the API part first. It will save you lots of implementation time if the API get accepted.
-->

**What this PR does / why we need it**:

Some cleanup after comments in https://github.com/envoyproxy/gateway/pull/5283
* Remove `PreserveXRequestID` from internal and map ClientTrafficPolicy `PreserveXRequestID` to RequestID=Preserve
* Mention `RequestID=Preserve` alternative in ClientTrafficPolicy description

**Which issue(s) this PR fixes**:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->
Fixes #

<!--
For any non-trivial changes, you need to provide a brief description of the changes in the release notes.
Please add the description to the release-notes/current.yaml file and include this file in the PR.
-->
Release Notes: No


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/envoyproxy/gateway/pull/5332?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 64.98%. Comparing base [(`f8c0b32`)](https://app.codecov.io/gh/envoyproxy/gateway/commit/f8c0b323a7f079be371e07a469af44ddf0ca7a7b?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) to head [(`6b8cabc`)](https://app.codecov.io/gh/envoyproxy/gateway/commit/6b8cabcd10802487047c54e22652f4647dafa62a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main    #5332   +/-   ##
=======================================
  Coverage   64.98%   64.98%           
=======================================
  Files         213      213           
  Lines       33474    33474           
=======================================
  Hits        21752    21752           
+ Misses      10396    10395    -1     
- Partials     1326     1327    +1     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/envoyproxy/gateway/pull/5332?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).

jukie: /retest
arkodg: thanks !
can you also add a test in https://github.com/envoyproxy/gateway/tree/main/test/cel-validation to validate the CEL validation
jukie: Rebased and updated with cel test

Patch:
diff --git a/api/v1alpha1/clienttrafficpolicy_types.go b/api/v1alpha1/clienttrafficpolicy_types.go
index c9ff0608c..d4766b0cd 100644
--- a/api/v1alpha1/clienttrafficpolicy_types.go
+++ b/api/v1alpha1/clienttrafficpolicy_types.go
@@ -101,6 +101,8 @@ type ClientTrafficPolicySpec struct {
 }
 
 // HeaderSettings provides configuration options for headers on the listener.
+//
+// +kubebuilder:validation:XValidation:rule="!(has(self.preserveXRequestID) && has(self.requestID))",message="preserveXRequestID and requestID cannot both be set."
 type HeaderSettings struct {
 	// EnableEnvoyHeaders configures Envoy Proxy to add the "X-Envoy-" headers to requests
 	// and responses.
@@ -131,8 +133,8 @@ type HeaderSettings struct {
 
 	// PreserveXRequestID configures Envoy to keep the X-Request-ID header if passed for a request that is edge
 	// (Edge request is the request from external clients to front Envoy) and not reset it, which is the current Envoy behaviour.
-	// It defaults to false.
-	// Deprecated: use RequestID instead
+	// Defaults to false and cannot be combined with RequestID.
+	// Deprecated: use RequestID=Preserve instead
 	//
 	// +optional
 	PreserveXRequestID *bool `json:"preserveXRequestID,omitempty"`
diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml
index c95a963af..c83d83564 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml
@@ -321,8 +321,8 @@ spec:
                     description: |-
                       PreserveXRequestID configures Envoy to keep the X-Request-ID header if passed for a request that is edge
                       (Edge request is the request from external clients to front Envoy) and not reset it, which is the current Envoy behaviour.
-                      It defaults to false.
-                      Deprecated: use RequestID instead
+                      Defaults to false and cannot be combined with RequestID.
+                      Deprecated: use RequestID=Preserve instead
                     type: boolean
                   requestID:
                     description: |-
@@ -396,6 +396,9 @@ spec:
                         > 0) ? (self.mode == ''AppendForward'' || self.mode == ''SanitizeSet'')
                         : true'
                 type: object
+                x-kubernetes-validations:
+                - message: preserveXRequestID and requestID cannot both be set.
+                  rule: '!(has(self.preserveXRequestID) && has(self.requestID))'
               healthCheck:
                 description: HealthCheck provides configuration for determining whether
                   the HTTP/HTTPS listener is healthy.
diff --git a/internal/gatewayapi/clienttrafficpolicy.go b/internal/gatewayapi/clienttrafficpolicy.go
index 30ff81d89..f2585a7dd 100644
--- a/internal/gatewayapi/clienttrafficpolicy.go
+++ b/internal/gatewayapi/clienttrafficpolicy.go
@@ -635,10 +635,11 @@ func translateListenerHeaderSettings(headerSettings *egv1a1.HeaderSettings, http
 		EnableEnvoyHeaders:      ptr.Deref(headerSettings.EnableEnvoyHeaders, false),
 		DisableRateLimitHeaders: ptr.Deref(headerSettings.DisableRateLimitHeaders, false),
 		WithUnderscoresAction:   ir.WithUnderscoresAction(ptr.Deref(headerSettings.WithUnderscoresAction, egv1a1.WithUnderscoresActionRejectRequest)),
-		PreserveXRequestID:      ptr.Deref(headerSettings.PreserveXRequestID, false),
 	}
 	if headerSettings.RequestID != nil {
 		httpIR.Headers.RequestID = (*ir.RequestIDAction)(headerSettings.RequestID)
+	} else if headerSettings.PreserveXRequestID != nil && *headerSettings.PreserveXRequestID {
+		httpIR.Headers.RequestID = ptr.To(ir.RequestIDActionPreserve)
 	}
 
 	if headerSettings.XForwardedClientCert != nil {
diff --git a/internal/ir/xds.go b/internal/ir/xds.go
index 4383ffb5d..073e4cbfb 100644
--- a/internal/ir/xds.go
+++ b/internal/ir/xds.go
@@ -644,12 +644,6 @@ type HeaderSettings struct {
 	// Refer to https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-enum-config-core-v3-httpprotocoloptions-headerswithunderscoresaction
 	WithUnderscoresAction WithUnderscoresAction `json:"withUnderscoresAction,omitempty" yaml:"withUnderscoresAction,omitempty"`
 
-	// PreserveXRequestID configures whether Envoy will keep the x-request-id header if passed for a request that is edge
-	// (Edge request is the request from external clients to front Envoy) and not reset it, which is the current Envoy behaviour.
-	// It defaults to false.
-	// Deprecated: use RequestID instead
-	PreserveXRequestID bool `json:"preserveXRequestID,omitempty" yaml:"preserveXRequestID,omitempty"`
-
 	// RequestID configures Envoy's behavior for handling the `X-Request-ID` header.
 	// Defaults to `Generate` and builds the `X-Request-ID` for every request and ignores pre-existing values from the edge.
 	// (An "edge request" refers to a request from an external client to the Envoy entrypoint.)
diff --git a/internal/xds/translator/listener.go b/internal/xds/translator/listener.go
index 6affdd7df..358dfe990 100644
--- a/internal/xds/translator/listener.go
+++ b/internal/xds/translator/listener.go
@@ -337,7 +337,6 @@ func (t *Translator) addHCMToXDSListener(xdsListener *listenerv3.Listener, irLis
 		},
 		Tracing:                       hcmTracing,
 		ForwardClientCertDetails:      buildForwardClientCertDetailsAction(irListener.Headers),
-		PreserveExternalRequestId:     ptr.Deref(irListener.Headers, ir.HeaderSettings{}).PreserveXRequestID,
 		EarlyHeaderMutationExtensions: buildEarlyHeaderMutation(irListener.Headers),
 	}
 
diff --git a/site/data/adopters.yaml b/site/data/adopters.yaml
index d86e3cf19..ae8bd50dc 100644
--- a/site/data/adopters.yaml
+++ b/site/data/adopters.yaml
@@ -39,3 +39,11 @@ adopters:
     logo: "/logos/sap.svg"
     url: "https://www.sap.com/index.html"
     description: ""
+  - name: "Tigera"
+    logo: "/logos/tigera.svg"
+    url: "https://www.tigera.io/"
+    description: ""
+  - name: "Kubermatic"
+    logo: "/logos/kubermatic.svg"
+    url: "https://www.kubermatic.com/"
+    description: "Kubermatic is using Envoy Gateway in KubeLB to provide L7 Load Balancing for multiple Kubernetes clusters using GatewayAPI."
diff --git a/site/static/logos/kubermatic.svg b/site/static/logos/kubermatic.svg
new file mode 100644
index 000000000..7536ba747
--- /dev/null
+++ b/site/static/logos/kubermatic.svg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 800 240" style="enable-background:new 0 0 800 240;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:#00517D;}
+</style>
+<g>
+	<polygon class="st0" points="165,64.8 165,95.1 125,114.8 125,84.6 	"/>
+	<polygon class="st0" points="215,84.6 215,114.8 175,95.1 175,64.8 	"/>
+	<polygon class="st0" points="165,144 165,174.3 125,154.6 125,124.3 	"/>
+	<polygon class="st0" points="215,124.3 215,154.6 175,174.3 175,144 	"/>
+	<polygon class="st0" points="115,84.8 87,65.2 87,175.2 115,155.5 	"/>
+</g>
+<path d="M298.8,140.8c-1-1.6-2.2-3.3-3.6-5c-1.4-1.8-2.8-3.5-4.3-5.1c-1.5-1.6-3.1-3.2-4.7-4.7c-1.6-1.5-3.2-2.8-4.7-3.8v18.7H274
+	V99.2h7.6v17.2c1.3-1.3,2.7-2.7,4.1-4.2s2.9-3,4.3-4.6c1.4-1.5,2.8-3,4-4.5c1.3-1.4,2.4-2.7,3.5-3.9h9.1c-1.3,1.5-2.7,3.1-4.2,4.7
+	c-1.5,1.6-3,3.3-4.6,5c-1.6,1.7-3.1,3.3-4.7,4.9c-1.6,1.6-3.1,3.2-4.6,4.7c1.7,1.3,3.4,2.8,5.1,4.5c1.7,1.7,3.5,3.5,5.1,5.5
+	c1.7,1.9,3.3,4,4.8,6.1c1.5,2.1,2.9,4.2,4.2,6.3H298.8z"/>
+<path d="M334.7,141.2c-2.8,0-5.3-0.4-7.3-1.2s-3.7-2-5.1-3.5c-1.3-1.5-2.3-3.2-3-5.2c-0.6-2-1-4.2-1-6.6v-26h7.6V124
+	c0,1.9,0.2,3.5,0.6,4.8c0.4,1.3,1,2.4,1.8,3.3s1.7,1.5,2.8,1.9c1.1,0.4,2.3,0.6,3.6,0.6s2.5-0.2,3.6-0.6c1.1-0.4,2-1,2.8-1.9
+	c0.8-0.8,1.4-1.9,1.8-3.3c0.4-1.3,0.6-2.9,0.6-4.8V98.8h7.6v26c0,2.4-0.3,4.6-1,6.6c-0.7,2-1.7,3.7-3,5.2c-1.3,1.5-3.1,2.6-5.1,3.5
+	C340,140.8,337.5,141.2,334.7,141.2z"/>
+<path d="M380.2,141.2c-2.2,0-4.4-0.1-6.7-0.2c-2.2-0.1-4.2-0.4-5.9-0.9V99.8c0.9-0.2,1.8-0.3,2.8-0.4c1-0.1,2-0.3,3.1-0.3
+	c1-0.1,2.1-0.1,3.1-0.2c1,0,2-0.1,2.9-0.1c2.5,0,4.9,0.2,7,0.6c2.2,0.4,4,1,5.6,1.9c1.6,0.9,2.8,2,3.7,3.5c0.9,1.4,1.3,3.2,1.3,5.3
+	c0,2-0.5,3.6-1.4,5c-0.9,1.4-2.3,2.5-3.9,3.4c2.5,0.8,4.4,2.1,5.6,3.7c1.2,1.6,1.8,3.7,1.8,6.2c0,4.3-1.6,7.5-4.7,9.6
+	C391.4,140.2,386.6,141.2,380.2,141.2z M375.1,116.1h5.3c2.9,0,5.1-0.4,6.8-1.2c1.6-0.8,2.5-2.3,2.5-4.4c0-2-0.9-3.4-2.5-4.3
+	c-1.7-0.8-3.9-1.3-6.6-1.3c-1.2,0-2.2,0-3.1,0.1s-1.7,0.1-2.3,0.2V116.1z M375.1,122v12.7c0.8,0.1,1.7,0.1,2.7,0.2
+	c1,0,1.8,0.1,2.6,0.1c1.6,0,3-0.1,4.4-0.3c1.3-0.2,2.5-0.5,3.5-1c1-0.5,1.8-1.2,2.3-2c0.6-0.8,0.9-1.9,0.9-3.2c0-2.4-0.9-4-2.6-4.9
+	c-1.7-0.9-4.1-1.4-7.1-1.4H375.1z"/>
+<path d="M413.9,140.8V99.2h26.7v6.4h-19.1v10.3h17v6.3h-17v12.2H442v6.4H413.9z"/>
+<path d="M468.5,99c6,0,10.6,1.1,13.8,3.3c3.2,2.2,4.8,5.6,4.8,10.1c0,5.6-2.8,9.5-8.3,11.5c0.8,0.9,1.6,2,2.6,3.4
+	c1,1.3,1.9,2.8,2.9,4.3c1,1.5,2,3.1,2.9,4.7c0.9,1.6,1.7,3.2,2.5,4.8h-8.5c-0.8-1.4-1.6-2.9-2.5-4.3c-0.9-1.5-1.8-2.9-2.7-4.3
+	c-0.9-1.4-1.8-2.7-2.7-3.9c-0.9-1.2-1.7-2.3-2.5-3.3c-0.6,0-1,0.1-1.4,0.1c-0.4,0-0.8,0-1.1,0h-3.7V141h-7.6v-41
+	c1.8-0.4,3.8-0.7,5.9-0.8C465,99.1,466.9,99,468.5,99z M469.1,105.5c-1.6,0-3.1,0.1-4.4,0.2v13.4h3.3c1.8,0,3.5-0.1,4.9-0.3
+	c1.4-0.2,2.6-0.6,3.5-1.1c0.9-0.5,1.7-1.2,2.1-2.1c0.5-0.9,0.7-2,0.7-3.4c0-1.3-0.2-2.4-0.7-3.2c-0.5-0.9-1.2-1.6-2.1-2.1
+	c-0.9-0.5-2-0.9-3.2-1.1S470.5,105.5,469.1,105.5z"/>
+<path d="M513.9,99.2c0.9,1.5,1.9,3.4,2.9,5.6c1.1,2.2,2.2,4.5,3.3,6.9c1.1,2.4,2.2,4.9,3.3,7.4c1.1,2.5,2.1,4.8,3,6.9
+	c0.9-2.1,1.9-4.4,3-6.9c1.1-2.5,2.2-5,3.3-7.4c1.1-2.4,2.2-4.7,3.3-6.9c1.1-2.2,2.1-4.1,2.9-5.6h6.8c0.4,3,0.7,6.3,1,9.7
+	c0.3,3.4,0.6,6.9,0.9,10.5c0.3,3.6,0.5,7.2,0.7,10.8s0.4,7.2,0.6,10.6h-7.4c-0.2-4.8-0.4-9.8-0.6-14.9c-0.2-5.1-0.6-10.1-1-14.9
+	c-0.4,0.9-1,2-1.6,3.3s-1.2,2.7-1.9,4.2c-0.7,1.5-1.4,3-2.1,4.6c-0.7,1.6-1.4,3.2-2,4.7c-0.7,1.5-1.3,2.9-1.8,4.2s-1,2.4-1.4,3.3
+	h-5.6c-0.4-0.9-0.9-2-1.4-3.4c-0.6-1.3-1.2-2.7-1.8-4.2s-1.3-3-2-4.6c-0.7-1.6-1.4-3.1-2.1-4.6c-0.7-1.5-1.3-2.9-1.9-4.2
+	c-0.6-1.3-1.1-2.4-1.6-3.3c-0.4,4.8-0.8,9.8-1,14.9c-0.2,5.1-0.4,10.1-0.6,14.9h-7.4c0.2-3.4,0.4-7,0.6-10.7c0.2-3.7,0.5-7.3,0.7-11
+	s0.6-7.1,0.9-10.5c0.3-3.4,0.7-6.5,1-9.4H513.9z"/>
+<path d="M592.3,140.8c-0.6-1.6-1.1-3.3-1.7-4.9c-0.6-1.6-1.2-3.2-1.7-4.9h-17.6c-0.6,1.7-1.1,3.3-1.7,5s-1.2,3.2-1.7,4.8H560
+	c1.6-4.4,3-8.5,4.4-12.3s2.8-7.3,4.1-10.7c1.3-3.4,2.7-6.6,4-9.6c1.3-3,2.7-6,4.1-9h7.2c1.4,3,2.8,6,4.1,9c1.3,3,2.6,6.2,4,9.6
+	c1.3,3.4,2.7,6.9,4.1,10.7c1.4,3.8,2.9,7.9,4.5,12.3H592.3z M580,107.3c-0.9,2.1-2,4.7-3.2,7.7s-2.4,6.3-3.7,9.9h13.7
+	c-1.3-3.6-2.5-6.9-3.7-10C582,111.9,580.9,109.3,580,107.3z"/>
+<path d="M638.2,99.2v6.5h-12.8v35h-7.6v-35H605v-6.5H638.2z"/>
+<path d="M650.8,99.2h7.6v41.6h-7.6V99.2z"/>
+<path d="M693.4,141.7c-3.1,0-5.9-0.5-8.4-1.4s-4.6-2.4-6.3-4.2c-1.7-1.9-3-4.1-4-6.8c-0.9-2.7-1.4-5.8-1.4-9.2
+	c0-3.5,0.5-6.6,1.6-9.2c1.1-2.7,2.5-5,4.4-6.8c1.8-1.9,4-3.3,6.5-4.2c2.5-1,5.1-1.4,8-1.4c1.7,0,3.3,0.1,4.7,0.4
+	c1.4,0.3,2.6,0.6,3.7,0.9c1,0.3,1.9,0.7,2.6,1c0.7,0.4,1.2,0.6,1.4,0.8l-2.2,6.2c-1-0.6-2.3-1.2-4.1-1.7c-1.8-0.5-3.7-0.8-5.8-0.8
+	c-1.8,0-3.5,0.3-5,0.9c-1.6,0.6-2.9,1.5-4,2.8c-1.1,1.2-2,2.8-2.7,4.7c-0.6,1.9-1,4.1-1,6.5c0,2.2,0.3,4.2,0.8,6.1
+	c0.5,1.8,1.3,3.4,2.3,4.8c1,1.3,2.4,2.4,4,3.1c1.6,0.7,3.5,1.1,5.8,1.1c2.7,0,4.9-0.3,6.5-0.8s3-1,3.9-1.5l2,6.2
+	c-0.5,0.3-1.1,0.6-1.9,1c-0.8,0.3-1.8,0.6-2.9,0.9c-1.1,0.3-2.4,0.5-3.8,0.7C696.5,141.6,695,141.7,693.4,141.7z"/>
+</svg>
diff --git a/site/static/logos/tigera.svg b/site/static/logos/tigera.svg
new file mode 100644
index 000000000..41fad5f53
--- /dev/null
+++ b/site/static/logos/tigera.svg
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 1000 832.8" style="enable-background:new 0 0 1000 832.8;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:#F99E20;}
+</style>
+<g id="Layer_2_1_">
+	<g id="Layer_1-2">
+		<path class="st0" d="M861.6,353.5c-16.1,20.6-31.7,34.6-53.4,46.8c11-14.9,15.4-33.1,15.3-53.7c-69.9,0-124.9,48.4-98.9,142.6
+			c14.8-1.2,23.3-11.9,31-23.7c0.8,13.4-2.4,28.3-12.1,45.3l6.3,15.3c-18,14-44.4,40.1-65.9,32.5c-56.4-70.5-144.6-90-259.8-14.6
+			c8.2-21.4,13.9-37.8,31.8-54.6c-21.1-0.8-61.1,5.1-91.7,23.3c0.9-79.8,9.2-163.4,38.3-266.3c-54.9,100.7-81.7,218.2-109,360.3
+			c-29.2-134.2-51.2-227.8-31-381.4c-58.3,11.1-123,52.4-174.9,86.8c62.3-88.1,196.7-183.3,255.2-201.7
+			c-28.3,49.2-46.5,117.2-50.8,172.7l26.3-2.6c-10.6,24.7-21.5,82.4-21.4,130.3c7.8-51,32-118.9,56.2-161.9l-32.2,3.2
+			c18.2-69,61.6-137.1,99.3-160.1c14.9-5.8,35.5-7.8,50.5-7.1c-4.4,28.9-26.5,175.8-15.3,243.6c0.4-72.6,33-276.4,59.4-328.6
+			c42,39.8,49.5,58.2,65.2,93.5c83.2,4.9,148,46.7,208.8,96.6c-1.4,5-4.8,9.2-9.5,11.5c16.2,6.2,56,30.3,71.3,44.2
+			c20.1,18.1,46,42.2,58.7,58.3l-23.8,40.2l-11-34.7l21.8-4l-29.1-0.4l11.8,42.4L861.6,353.5L861.6,353.5z M744.2,247L721.9,217
+			l-60.3-18.7l35.1,31.1l20.9-1.2L744.2,247z"/>
+		<polygon points="156.3,700.4 156.3,734.5 98.4,734.5 98.4,832.6 58,832.6 58,734.5 0,734.5 0,700.4 		"/>
+		<rect x="179.1" y="700.4" width="40.3" height="132.2"/>
+		<path d="M378,744.6c-0.5-8.3-4.6-12.6-12.6-13c-4.5-0.2-13.5-0.3-27.2-0.3l-25.1,0.1c-8.5,0.2-14.5,1.4-18.1,3.8
+			c-4.1,2.8-6.4,8.3-6.8,16.6c-0.3,4.8-0.4,9.6-0.4,14.3c-0.1,5.5,0.2,10.9,0.9,16.3c1,9.6,5.5,14.7,13.2,15.5
+			c5,0.5,10.1,0.8,15.2,0.7h16.1l27.4-0.1c12.2-0.1,18.4-4,18.6-11.8v-4.3h-50.3v-27.1h90.7v4.7c0,22.6-0.4,36.8-1.2,42.6
+			c-1.1,6.7-4.1,12.9-8.8,17.7c-4.6,5-10.7,8.2-17.4,9.2c-4.9,1-9.9,1.7-14.9,1.9c-11.7,0.9-27.4,1.3-47.1,1.2l-28.1-0.2
+			c-12-0.2-20.8-1.1-26.5-2.7c-8.8-2.2-16.3-7.9-20.7-15.8c-4.1-7-6.4-17.1-6.9-30.4c-0.4-10.6-0.6-21.2-0.6-31.8
+			c-0.1-4.5,0-7.7,0.1-9.8c0.1-5.3,1.1-10.6,2.9-15.7c4.9-15,16.2-24,34.1-26.8c4.7-0.9,9.5-1.4,14.3-1.6c6.9-0.3,18-0.5,33.3-0.6
+			c19.3,0,34,0.2,43.9,0.5c27.8,0.7,42,13.3,42.5,38v8.9L378,744.6z"/>
+		<polygon points="444.3,700.4 590.2,700.4 590.2,731.3 484.8,731.3 484.8,749.4 584.3,749.4 584.3,778.1 484.8,778.1 484.8,801.8 
+			591.3,801.8 591.3,832.6 444.4,832.6 444.4,700.4 		"/>
+		<path d="M779.5,768.2c3-5.5,4.5-13.7,4.5-24.6c0-6.6-0.8-13.2-2.1-19.7c-0.7-3.3-2-6.4-3.7-9.3c-4.5-7.7-12.9-12.1-25.2-13.4
+			c-5.5-0.6-11-0.9-16.5-0.9H619.7v132.2h40.4v-32.9h64c8.2-0.1,13.4,1.4,15.5,4.3c2,2.5,2.9,8,2.9,16.4l0.3,12.3h40.3v-16.3
+			c0-11.5-1.3-19.5-4-23.9s-9.5-8.2-20.7-11.3C769.5,778,776.5,773.7,779.5,768.2z M737.6,763.8c-2.7,1.1-5.5,1.6-8.3,1.5
+			c-4.5,0.2-8.8,0.2-12.8,0.2H660v-31.1h55.3l11.8,0.3c6.1,0.1,10.2,1,12.2,3c2.9,2.5,4.2,6.4,4.2,11.8
+			C743.5,757.3,741.4,761.9,737.6,763.8L737.6,763.8z"/>
+		<path d="M926.9,700.4h-51.2l-73.1,132.2h45.8l11.9-22.7v-0.1h81.7v0.1l12.3,22.7h45.7L926.9,700.4z M925.5,779.1l-0.1-0.2h-49
+			l-0.1,0.2V779h0.1l25-45l24,45h0.1V779.1z"/>
+		<polygon points="876.3,777.6 876.4,777.4 876.3,777.4 		"/>
+		<polygon points="925.5,777.6 925.5,777.4 925.4,777.4 		"/>
+	</g>
+</g>
+</svg>


Test patch:
diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-headers-error.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-headers-error.out.yaml
index c7dbc8bb2..235a6c68a 100644
--- a/internal/gatewayapi/testdata/clienttrafficpolicy-headers-error.out.yaml
+++ b/internal/gatewayapi/testdata/clienttrafficpolicy-headers-error.out.yaml
@@ -110,7 +110,7 @@ xdsIR:
     - address: 0.0.0.0
       headers:
         enableEnvoyHeaders: true
-        preserveXRequestID: true
+        requestID: Preserve
         withUnderscoresAction: Allow
       hostnames:
       - '*'
diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-headers.in.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-headers.in.yaml
index afab602fb..cfb4bf0e2 100644
--- a/internal/gatewayapi/testdata/clienttrafficpolicy-headers.in.yaml
+++ b/internal/gatewayapi/testdata/clienttrafficpolicy-headers.in.yaml
@@ -8,7 +8,6 @@ clientTrafficPolicies:
     headers:
       enableEnvoyHeaders: true
       withUnderscoresAction: Allow
-      preserveXRequestID: true
       requestID: PreserveOrGenerate
       earlyRequestHeaders:
         add:
diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-headers.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-headers.out.yaml
index 46150adf6..033233426 100644
--- a/internal/gatewayapi/testdata/clienttrafficpolicy-headers.out.yaml
+++ b/internal/gatewayapi/testdata/clienttrafficpolicy-headers.out.yaml
@@ -22,7 +22,6 @@ clientTrafficPolicies:
         - name: my-set-header
           value: my-set-header-value
       enableEnvoyHeaders: true
-      preserveXRequestID: true
       requestID: PreserveOrGenerate
       withUnderscoresAction: Allow
     targetRef:
@@ -156,7 +155,6 @@ xdsIR:
         earlyRemoveRequestHeaders:
         - my-removed-header
         enableEnvoyHeaders: true
-        preserveXRequestID: true
         requestID: PreserveOrGenerate
         withUnderscoresAction: Allow
       hostnames:
@@ -186,7 +184,6 @@ xdsIR:
         earlyRemoveRequestHeaders:
         - my-removed-header
         enableEnvoyHeaders: true
-        preserveXRequestID: true
         requestID: PreserveOrGenerate
         withUnderscoresAction: Allow
       hostnames:
diff --git a/internal/xds/translator/testdata/in/xds-ir/headers-with-preserve-x-request-id.yaml b/internal/xds/translator/testdata/in/xds-ir/headers-with-preserve-x-request-id.yaml
deleted file mode 100644
index ec74370f2..000000000
--- a/internal/xds/translator/testdata/in/xds-ir/headers-with-preserve-x-request-id.yaml
+++ /dev/null
@@ -1,34 +0,0 @@
-http:
-- name: "first-listener"
-  address: "::"
-  port: 8081
-  hostnames:
-  - "*"
-  routes:
-  - name: "first-route"
-    hostname: "*"
-    destination:
-      name: "first-route-dest"
-      settings:
-      - endpoints:
-        - host: "1.1.1.1"
-          port: 8081
-        name: "first-route-dest/backend/0"
-  headers:
-    preserveXRequestID: true
-- name: "second-listener"
-  address: "::"
-  port: 8082
-  hostnames:
-  - "*"
-  routes:
-  - name: "second-route"
-    hostname: "*"
-    destination:
-      name: "second-route-dest"
-      settings:
-      - endpoints:
-        - host: "2.2.2.2"
-          port: 8082
-        name: "second-route-dest/backend/0"
-
diff --git a/internal/xds/translator/testdata/out/xds-ir/headers-with-preserve-x-request-id.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/headers-with-preserve-x-request-id.clusters.yaml
deleted file mode 100755
index ba595752d..000000000
--- a/internal/xds/translator/testdata/out/xds-ir/headers-with-preserve-x-request-id.clusters.yaml
+++ /dev/null
@@ -1,34 +0,0 @@
-- circuitBreakers:
-    thresholds:
-    - maxRetries: 1024
-  commonLbConfig:
-    localityWeightedLbConfig: {}
-  connectTimeout: 10s
-  dnsLookupFamily: V4_PREFERRED
-  edsClusterConfig:
-    edsConfig:
-      ads: {}
-      resourceApiVersion: V3
-    serviceName: first-route-dest
-  ignoreHealthOnHostRemoval: true
-  lbPolicy: LEAST_REQUEST
-  name: first-route-dest
-  perConnectionBufferLimitBytes: 32768
-  type: EDS
-- circuitBreakers:
-    thresholds:
-    - maxRetries: 1024
-  commonLbConfig:
-    localityWeightedLbConfig: {}
-  connectTimeout: 10s
-  dnsLookupFamily: V4_PREFERRED
-  edsClusterConfig:
-    edsConfig:
-      ads: {}
-      resourceApiVersion: V3
-    serviceName: second-route-dest
-  ignoreHealthOnHostRemoval: true
-  lbPolicy: LEAST_REQUEST
-  name: second-route-dest
-  perConnectionBufferLimitBytes: 32768
-  type: EDS
diff --git a/internal/xds/translator/testdata/out/xds-ir/headers-with-preserve-x-request-id.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/headers-with-preserve-x-request-id.endpoints.yaml
deleted file mode 100755
index 9ad09dd91..000000000
--- a/internal/xds/translator/testdata/out/xds-ir/headers-with-preserve-x-request-id.endpoints.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
-- clusterName: first-route-dest
-  endpoints:
-  - lbEndpoints:
-    - endpoint:
-        address:
-          socketAddress:
-            address: 1.1.1.1
-            portValue: 8081
-      loadBalancingWeight: 1
-    loadBalancingWeight: 1
-    locality:
-      region: first-route-dest/backend/0
-- clusterName: second-route-dest
-  endpoints:
-  - lbEndpoints:
-    - endpoint:
-        address:
-          socketAddress:
-            address: 2.2.2.2
-            portValue: 8082
-      loadBalancingWeight: 1
-    loadBalancingWeight: 1
-    locality:
-      region: second-route-dest/backend/0
diff --git a/internal/xds/translator/testdata/out/xds-ir/headers-with-preserve-x-request-id.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/headers-with-preserve-x-request-id.listeners.yaml
deleted file mode 100644
index de527446a..000000000
--- a/internal/xds/translator/testdata/out/xds-ir/headers-with-preserve-x-request-id.listeners.yaml
+++ /dev/null
@@ -1,65 +0,0 @@
-- address:
-    socketAddress:
-      address: '::'
-      portValue: 8081
-  defaultFilterChain:
-    filters:
-    - name: envoy.filters.network.http_connection_manager
-      typedConfig:
-        '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
-        commonHttpProtocolOptions:
-          headersWithUnderscoresAction: REJECT_REQUEST
-        http2ProtocolOptions:
-          initialConnectionWindowSize: 1048576
-          initialStreamWindowSize: 65536
-          maxConcurrentStreams: 100
-        httpFilters:
-        - name: envoy.filters.http.router
-          typedConfig:
-            '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
-            suppressEnvoyHeaders: true
-        normalizePath: true
-        preserveExternalRequestId: true
-        rds:
-          configSource:
-            ads: {}
-            resourceApiVersion: V3
-          routeConfigName: first-listener
-        serverHeaderTransformation: PASS_THROUGH
-        statPrefix: http-8081
-        useRemoteAddress: true
-    name: first-listener
-  name: first-listener
-  perConnectionBufferLimitBytes: 32768
-- address:
-    socketAddress:
-      address: '::'
-      portValue: 8082
-  defaultFilterChain:
-    filters:
-    - name: envoy.filters.network.http_connection_manager
-      typedConfig:
-        '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
-        commonHttpProtocolOptions:
-          headersWithUnderscoresAction: REJECT_REQUEST
-        http2ProtocolOptions:
-          initialConnectionWindowSize: 1048576
-          initialStreamWindowSize: 65536
-          maxConcurrentStreams: 100
-        httpFilters:
-        - name: envoy.filters.http.router
-          typedConfig:
-            '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
-            suppressEnvoyHeaders: true
-        normalizePath: true
-        rds:
-          configSource:
-            ads: {}
-            resourceApiVersion: V3
-          routeConfigName: second-listener
-        serverHeaderTransformation: PASS_THROUGH
-        statPrefix: http-8082
-        useRemoteAddress: true
-    name: second-listener
-  name: second-listener
-  perConnectionBufferLimitBytes: 32768
diff --git a/internal/xds/translator/testdata/out/xds-ir/headers-with-preserve-x-request-id.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/headers-with-preserve-x-request-id.routes.yaml
deleted file mode 100755
index ff93cfff3..000000000
--- a/internal/xds/translator/testdata/out/xds-ir/headers-with-preserve-x-request-id.routes.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-- ignorePortInHostMatching: true
-  name: first-listener
-  virtualHosts:
-  - domains:
-    - '*'
-    name: first-listener/*
-    routes:
-    - match:
-        prefix: /
-      name: first-route
-      route:
-        cluster: first-route-dest
-        upgradeConfigs:
-        - upgradeType: websocket
-- ignorePortInHostMatching: true
-  name: second-listener
-  virtualHosts:
-  - domains:
-    - '*'
-    name: second-listener/*
-    routes:
-    - match:
-        prefix: /
-      name: second-route
-      route:
-        cluster: second-route-dest
-        upgradeConfigs:
-        - upgradeType: websocket
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index 32c07223e..e5361a12c 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -2268,7 +2268,7 @@ _Appears in:_
 | `disableRateLimitHeaders` | _boolean_ |  false  |  | DisableRateLimitHeaders configures Envoy Proxy to omit the "X-RateLimit-" response headers<br />when rate limiting is enabled. |
 | `xForwardedClientCert` | _[XForwardedClientCert](#xforwardedclientcert)_ |  false  |  | XForwardedClientCert configures how Envoy Proxy handle the x-forwarded-client-cert (XFCC) HTTP header.<br />x-forwarded-client-cert (XFCC) is an HTTP header used to forward the certificate<br />information of part or all of the clients or proxies that a request has flowed through,<br />on its way from the client to the server.<br />Envoy proxy may choose to sanitize/append/forward the XFCC header before proxying the request.<br />If not set, the default behavior is sanitizing the XFCC header. |
 | `withUnderscoresAction` | _[WithUnderscoresAction](#withunderscoresaction)_ |  false  |  | WithUnderscoresAction configures the action to take when an HTTP header with underscores<br />is encountered. The default action is to reject the request. |
-| `preserveXRequestID` | _boolean_ |  false  |  | PreserveXRequestID configures Envoy to keep the X-Request-ID header if passed for a request that is edge<br />(Edge request is the request from external clients to front Envoy) and not reset it, which is the current Envoy behaviour.<br />It defaults to false.<br />Deprecated: use RequestID instead |
+| `preserveXRequestID` | _boolean_ |  false  |  | PreserveXRequestID configures Envoy to keep the X-Request-ID header if passed for a request that is edge<br />(Edge request is the request from external clients to front Envoy) and not reset it, which is the current Envoy behaviour.<br />Defaults to false and cannot be combined with RequestID.<br />Deprecated: use RequestID=Preserve instead |
 | `requestID` | _[RequestIDAction](#requestidaction)_ |  false  |  | RequestID configures Envoy's behavior for handling the `X-Request-ID` header.<br />Defaults to `Generate` and builds the `X-Request-ID` for every request and ignores pre-existing values from the edge.<br />(An "edge request" refers to a request from an external client to the Envoy entrypoint.) |
 | `earlyRequestHeaders` | _[HTTPHeaderFilter](#httpheaderfilter)_ |  false  |  | EarlyRequestHeaders defines settings for early request header modification, before envoy performs<br />routing, tracing and built-in header manipulation. |
 
diff --git a/test/cel-validation/clienttrafficpolicy_test.go b/test/cel-validation/clienttrafficpolicy_test.go
index 942afea16..e4e7f603f 100644
--- a/test/cel-validation/clienttrafficpolicy_test.go
+++ b/test/cel-validation/clienttrafficpolicy_test.go
@@ -592,6 +592,30 @@ func TestClientTrafficPolicyTarget(t *testing.T) {
 			},
 			wantErrors: []string{},
 		},
+		{
+			desc: "invalid x-request-id header setting",
+			mutate: func(ctp *egv1a1.ClientTrafficPolicy) {
+				ctp.Name = "ctp-headers"
+				ctp.Spec = egv1a1.ClientTrafficPolicySpec{
+					PolicyTargetReferences: egv1a1.PolicyTargetReferences{
+						TargetRef: &gwapiv1a2.LocalPolicyTargetReferenceWithSectionName{
+							LocalPolicyTargetReference: gwapiv1a2.LocalPolicyTargetReference{
+								Group: gwapiv1a2.Group("gateway.networking.k8s.io"),
+								Kind:  gwapiv1a2.Kind("Gateway"),
+								Name:  gwapiv1a2.ObjectName("eg"),
+							},
+						},
+					},
+					Headers: &egv1a1.HeaderSettings{
+						PreserveXRequestID: ptr.To(true),
+						RequestID:          ptr.To(egv1a1.RequestIDActionGenerate),
+					},
+				}
+			},
+			wantErrors: []string{
+				"ClientTrafficPolicy.gateway.envoyproxy.io \"ctp-headers\" is invalid: spec.headers: Invalid value: \"object\": preserveXRequestID and requestID cannot both be set.",
+			},
+		},
 	}
 
 	for _, tc := range cases {