Repository: nginx/nginx-gateway-fabric

Issue:
ObservabilityPolicy:  got TargetConflict error when creating ObservabilityPolicy for two totally seperated applications
**Describe the bug**
`I am playing around the gateway fabric and trying to configure tracing for my applications. With one application, the configuration worked fine. But with two applications in two different namespaces, I am getting:

ObservabilityPolicy for app1 is complaining app2:
      Message:               Policy cannot be applied to target "app2/app2" since another Route "app2/app2" shares a hostname:port/path combination with this target
      Observed Generation:   2
      Reason:                TargetConflict

ObservabilityPolicy for app2 is complaining app1:
      Message:               Policy cannot be applied to target "app1/app1" since another Route "app1/app1" shares a hostname:port/path combination with this target
      Observed Generation:   1
      Reason:                TargetConflict
`
**To Reproduce**
Steps to reproduce the behavior:
1. HTTPToutes:
`apiVersion: v1
items:
- apiVersion: gateway.networking.k8s.io/v1
  kind: HTTPRoute
  metadata:
    creationTimestamp: "2025-05-14T21:04:22Z"
    generation: 12
    name: app1
    namespace: app1
    resourceVersion: "60634620"
    uid: 823cfaf9-9306-403c-abde-532430422792
  spec:
    hostnames:
    - app1.playground.testapis.net
    parentRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: central-gateway
      namespace: nginx-gateway
    rules:
    - backendRefs:
      - group: ""
        kind: Service
        name: app1
        namespace: app1
        port: 50080
        weight: 1
      filters:
      - extensionRef:
          group: gateway.nginx.org
          kind: SnippetsFilter
          name: app1-logging
        type: ExtensionRef
      - extensionRef:
          group: gateway.nginx.org
          kind: SnippetsFilter
          name: app1-ratelimit
        type: ExtensionRef
      matches:
      - path:
          type: PathPrefix
          value: /
  status:
    parents:
    - conditions:
      - lastTransitionTime: "2025-05-23T14:05:58Z"
        message: The route is accepted
        observedGeneration: 12
        reason: Accepted
        status: "True"
        type: Accepted
      - lastTransitionTime: "2025-05-23T14:05:58Z"
        message: All references are resolved
        observedGeneration: 12
        reason: ResolvedRefs
        status: "True"
        type: ResolvedRefs
      controllerName: gateway.nginx.org/nginx-gateway-controller
      parentRef:
        group: gateway.networking.k8s.io
        kind: Gateway
        name: central-gateway
        namespace: nginx-gateway
- apiVersion: gateway.networking.k8s.io/v1
  kind: HTTPRoute
  metadata:
    creationTimestamp: "2025-05-23T13:47:37Z"
    generation: 2
    name: app2
    namespace: app2
    resourceVersion: "60634618"
    uid: c975562d-7241-43cb-9bba-b22bb2e0a3cc
  spec:
    hostnames:
    - app2.playground.testapis.net
    parentRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: central-gateway
      namespace: nginx-gateway
    rules:
    - backendRefs:
      - group: ""
        kind: Service
        name: app2
        namespace: app2
        port: 51080
        weight: 1
      filters:
      - extensionRef:
          group: gateway.nginx.org
          kind: SnippetsFilter
          name: app2-logging
        type: ExtensionRef
      matches:
      - path:
          type: PathPrefix
          value: /
  status:
    parents:
    - conditions:
      - lastTransitionTime: "2025-05-23T14:05:58Z"
        message: The route is accepted
        observedGeneration: 2
        reason: Accepted
        status: "True"
        type: Accepted
      - lastTransitionTime: "2025-05-23T14:05:58Z"
        message: All references are resolved
        observedGeneration: 2
        reason: ResolvedRefs
        status: "True"
        type: ResolvedRefs
      controllerName: gateway.nginx.org/nginx-gateway-controller
      parentRef:
        group: gateway.networking.k8s.io
        kind: Gateway
        name: central-gateway
        namespace: nginx-gateway`

ObservabilityPolicy configs:
`apiVersion: v1
items:
- apiVersion: gateway.nginx.org/v1alpha2
  kind: ObservabilityPolicy
  metadata:
    creationTimestamp: "2025-05-22T18:23:49Z"
    generation: 2
    name: app1-observability
    namespace: app1
    resourceVersion: "60627544"
    uid: 241ba77f-7860-4bb7-832e-32e393ced533
  spec:
    targetRefs:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      name: app1
    tracing:
      ratio: 100
      spanAttributes:
      - key: app1
        value: app1
      strategy: ratio
  status:
    ancestors:
    - ancestorRef:
        group: gateway.networking.k8s.io
        kind: HTTPRoute
        name: app1
        namespace: app1
      conditions:
      - lastTransitionTime: "2025-05-23T13:47:37Z"
        message: Policy cannot be applied to target "app2/app2" since another Route
          "app2/app2" shares a hostname:port/path combination with this target
        observedGeneration: 2
        reason: TargetConflict
        status: "False"
        type: Accepted
      controllerName: gateway.nginx.org/nginx-gateway-controller
- apiVersion: gateway.nginx.org/v1alpha2
  kind: ObservabilityPolicy
  metadata:
    creationTimestamp: "2025-05-23T14:30:03Z"
    generation: 1
    name: app2-observability
    namespace: app2
    resourceVersion: "60643831"
    uid: cdd669f5-17dc-43f8-91a0-8966cc1bad83
  spec:
    targetRefs:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      name: app2
    tracing:
      ratio: 100
      spanAttributes:
      - key: app2
        value: app2
      strategy: ratio
  status:
    ancestors:
    - ancestorRef:
        group: gateway.networking.k8s.io
        kind: HTTPRoute
        name: app2
        namespace: app2
      conditions:
      - lastTransitionTime: "2025-05-23T14:30:04Z"
        message: Policy cannot be applied to target "app1/app1" since another Route
          "app1/app1" shares a hostname:port/path combination with this target
        observedGeneration: 1
        reason: TargetConflict
        status: "False"
        type: Accepted
      controllerName: gateway.nginx.org/nginx-gateway-controller
kind: List
metadata:
  resourceVersion: ""`


**Your environment**
* Version of the NGINX Gateway Fabric - release version or a specific commit. The first line of the nginx-gateway container logs includes the commit info.
`{"level":"info","ts":"2025-05-23T13:00:37Z","msg":"Starting NGINX Gateway Fabric in static mode","version":"1.6.2","commit":"532db6a20b2912fe397211eef9f8d564d46a4bdd","date":"2025-03-11T17:28:32Z","dirty":"false"}`
* Version of Kubernetes
`Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.31.8`
* Kubernetes platform: AKS
* Details on how you expose the NGINX Gateway Fabric Pod (e.g. Service of type LoadBalancer or port-forward)
* Logs of NGINX container: `kubectl -n <nginx-deployment-namespace> logs deployments/<nginx-deployment>`
* NGINX Configuration: `kubectl -n <nginx-deployment-namespace> exec -it deployments/<nginx-deployment> -- nginx -T`

**Additional context**
Following section was injected in http.conf file:
`otel_exporter {
⤑   endpoint opentelemetry-collector-i.estapis.net:4317;
}

otel_service_name ngf:nginx-gateway:central-gateway;
split_clients $otel_trace_id $otel_ratio_100 {
⤑   100% on;
⤑   *  off;
}`

Discussion:
@bjee19: Hey @hongyecc , thanks for submitting this issue. I'm currently trying to reproduce the issue, however I'm having some difficulty. 

Do you think you could provide the yaml file for the Gateway you deployed? Also having the yaml files for the HTTPRoutes/Observability policies would help a lot, but aren't necessary. @hongyecc: @bjee19 thanks for looking into the problem ... here is the gateway yaml I used. Feel free to let me know if you need anything else 
`
apiVersion: v1
items:
- apiVersion: gateway.networking.k8s.io/v1
  kind: Gateway
  metadata:
    creationTimestamp: "2025-05-12T23:40:47Z"
    generation: 1
    name: central-gateway
    namespace: nginx-gateway
    resourceVersion: "60627545"
    uid: ab0610f2-4685-4a5b-a78a-f8420969fa54
  spec:
    gatewayClassName: nginx
    listeners:
    - allowedRoutes:
        namespaces:
          from: All
      hostname: '*.playground.testapis.net'
      name: http
      port: 80
      protocol: HTTP
    - allowedRoutes:
        namespaces:
          from: All
      hostname: '*.playground.testapis.net'
      name: https
      port: 443
      protocol: HTTPS
      tls:
        certificateRefs:
        - group: ""
          kind: Secret
          name: playground.testapis.net
          namespace: nginx-gateway
        mode: Terminate
`@bjee19: Hey @hongyecc, thanks for trying out NGINX Gateway Fabric and reporting this bug. It ended up being an issue with how we processed routes with no sectionName in their parentRefs, specifically when the Gateway listeners they try to attach to have the same hostname. 

Anyways, the fix is now merged into main and will be in our next stable release, 2.0, coming next week with some big feature updates. If you end up trying out our 2.0, hopefully you won't see this same issue. 

However, as I was trying to recreate your issue, I realized a quick fix would be to specify the sectionName in the HTTPRoute parentRef section. I'm not sure if you wanted the route to attach to all the Gateway listeners, but if you declare just the http or the https listener, your set up will be fixed. If you wanted the route to attach to all the Gateway listeners, then that won't work, but it should in the 2.0 release! 

Again thanks for submitting this bug and I hope you explore our 2.0! @hongyecc: @bjee19 thanks for the quick response and fix. I am using nginx ingress controller for my current aks cluster deployment. My initial thought was to mimic that, with one gateway to handle all routes and bind to all listeners. http request will be redirected to https eventually. But I saw there was a feature request to have multiple gateways so the traffic can be totally for different applications, which is something I want to check out too later. Glad version 2.0 will be out soon and I will definitely check that out.

BTW, is there a slack channel of mailing list I can join to ask questions, etc? I googled around and did not find one. There is one slack channel listed in F5's website but the workspace was deleted.@bjee19: @hongyecc Nice, cool to hear about your reason for checking NGF out. 

We've switched from using our previous public NGINX slack channel to using the [NGINX Community Fourm](https://community.nginx.org/), however, reaching out to us specifically here in the Github discussions or opening an issue would be your best way to contact us with questions. Either one works!

Solution patch:
diff --git a/internal/controller/state/graph/route_common.go b/internal/controller/state/graph/route_common.go
index c702f1d4..1cbb2fc4 100644
--- a/internal/controller/state/graph/route_common.go
+++ b/internal/controller/state/graph/route_common.go
@@ -277,35 +277,61 @@ func buildSectionNameRefs(
 	routeNamespace string,
 	gws map[types.NamespacedName]*Gateway,
 ) ([]ParentRef, error) {
-	sectionNameRefs := make([]ParentRef, 0, len(parentRefs))
-
 	type key struct {
 		gwNsName    types.NamespacedName
 		sectionName string
 	}
 	uniqueSectionsPerGateway := make(map[key]struct{})
 
+	sectionNameRefs := make([]ParentRef, 0, len(parentRefs))
+
+	checkUniqueSections := func(key key) error {
+		if _, exist := uniqueSectionsPerGateway[key]; exist {
+			return fmt.Errorf("duplicate section name %q for Gateway %s", key.sectionName, key.gwNsName.String())
+		}
+
+		uniqueSectionsPerGateway[key] = struct{}{}
+		return nil
+	}
+
 	for i, p := range parentRefs {
 		gw := findGatewayForParentRef(p, routeNamespace, gws)
 		if gw == nil {
 			continue
 		}
 
-		var sectionName string
-		if p.SectionName != nil {
-			sectionName = string(*p.SectionName)
-		}
-
 		gwNsName := client.ObjectKeyFromObject(gw.Source)
 		k := key{
-			gwNsName:    gwNsName,
-			sectionName: sectionName,
+			gwNsName: gwNsName,
+		}
+
+		// If there is no section name, we create ParentRefs for each listener in the gateway
+		if p.SectionName == nil {
+			for _, l := range gw.Listeners {
+				k.sectionName = string(l.Source.Name)
+
+				if err := checkUniqueSections(k); err != nil {
+					return nil, err
+				}
+
+				sectionNameRefs = append(sectionNameRefs, ParentRef{
+					// if the ParentRefs we create are for each listener in the same gateway, we keep the
+					// parentRefIndex the same so when we look at a route's parentRef's we can see
+					// if the parentRef is a unique parentRef or one we created internally
+					Idx:         i,
+					Gateway:     CreateParentRefGateway(gw),
+					SectionName: &l.Source.Name,
+					Port:        p.Port,
+				})
+			}
+
+			continue
 		}
 
-		if _, exist := uniqueSectionsPerGateway[k]; exist {
-			return nil, fmt.Errorf("duplicate section name %q for Gateway %s", sectionName, gwNsName.String())
+		k.sectionName = string(*p.SectionName)
+		if err := checkUniqueSections(k); err != nil {
+			return nil, err
 		}
-		uniqueSectionsPerGateway[k] = struct{}{}
 
 		sectionNameRefs = append(sectionNameRefs, ParentRef{
 			Idx:         i,
diff --git a/internal/controller/status/prepare_requests.go b/internal/controller/status/prepare_requests.go
index 1da7f8e3..4cb8fd5e 100644
--- a/internal/controller/status/prepare_requests.go
+++ b/internal/controller/status/prepare_requests.go
@@ -95,6 +95,41 @@ func PrepareRouteRequests(
 	return reqs
 }
 
+// removeDuplicateIndexParentRefs removes duplicate ParentRefs by Idx, keeping the first occurrence.
+// If an Idx is duplicated, the SectionName for the stored ParentRef is nil.
+func removeDuplicateIndexParentRefs(parentRefs []graph.ParentRef) []graph.ParentRef {
+	idxToParentRef := make(map[int][]graph.ParentRef)
+	for _, ref := range parentRefs {
+		idxToParentRef[ref.Idx] = append(idxToParentRef[ref.Idx], ref)
+	}
+
+	results := make([]graph.ParentRef, len(idxToParentRef))
+
+	for idx, refs := range idxToParentRef {
+		if len(refs) == 1 {
+			results[idx] = refs[0]
+			continue
+		}
+
+		winningParentRef := graph.ParentRef{
+			Idx:        idx,
+			Gateway:    refs[0].Gateway,
+			Attachment: refs[0].Attachment,
+		}
+
+		for _, ref := range refs {
+			if ref.Attachment.Attached {
+				if len(ref.Attachment.FailedConditions) == 0 || winningParentRef.Attachment == nil {
+					winningParentRef.Attachment = ref.Attachment
+				}
+			}
+		}
+		results[idx] = winningParentRef
+	}
+
+	return results
+}
+
 func prepareRouteStatus(
 	gatewayCtlrName string,
 	parentRefs []graph.ParentRef,
@@ -103,11 +138,17 @@ func prepareRouteStatus(
 	transitionTime metav1.Time,
 	srcGeneration int64,
 ) v1.RouteStatus {
-	parents := make([]v1.RouteParentStatus, 0, len(parentRefs))
+	// If a route did not specify a sectionName in its parentRefs section, it will attempt to attach to all available
+	// listeners. In this case, parentRefs will be created and attached to the route for each attachable listener.
+	// These parentRefs will all have the same Idx, and in order to not duplicate route statuses for the same Gateway,
+	// we need to remove these duplicates. Additionally, we remove the sectionName.
+	processedParentRefs := removeDuplicateIndexParentRefs(parentRefs)
+
+	parents := make([]v1.RouteParentStatus, 0, len(processedParentRefs))
 
 	defaultConds := conditions.NewDefaultRouteConditions()
 
-	for _, ref := range parentRefs {
+	for _, ref := range processedParentRefs {
 		failedAttachmentCondCount := 0
 		if ref.Attachment != nil {
 			failedAttachmentCondCount = len(ref.Attachment.FailedConditions)



Test patch:
diff --git a/internal/controller/state/graph/graph_test.go b/internal/controller/state/graph/graph_test.go
index 9006e5bd..748a3aa2 100644
--- a/internal/controller/state/graph/graph_test.go
+++ b/internal/controller/state/graph/graph_test.go
@@ -772,6 +772,32 @@ func TestBuildGraph(t *testing.T) {
 		Attachable: true,
 		Source:     tr,
 		ParentRefs: []ParentRef{
+			{
+				Idx: 0,
+				Gateway: &ParentRefGateway{
+					NamespacedName:      client.ObjectKeyFromObject(gw1.Source),
+					EffectiveNginxProxy: np1Effective,
+				},
+				Attachment: &ParentRefAttachmentStatus{
+					AcceptedHostnames: map[string][]string{},
+					Attached:          false,
+					FailedConditions:  []conditions.Condition{conditions.NewRouteNotAllowedByListeners()},
+				},
+				SectionName: &gw1.Source.Spec.Listeners[0].Name,
+			},
+			{
+				Idx: 0,
+				Gateway: &ParentRefGateway{
+					NamespacedName:      client.ObjectKeyFromObject(gw1.Source),
+					EffectiveNginxProxy: np1Effective,
+				},
+				Attachment: &ParentRefAttachmentStatus{
+					AcceptedHostnames: map[string][]string{},
+					Attached:          false,
+					FailedConditions:  []conditions.Condition{conditions.NewRouteNotAllowedByListeners()},
+				},
+				SectionName: &gw1.Source.Spec.Listeners[1].Name,
+			},
 			{
 				Idx: 0,
 				Gateway: &ParentRefGateway{
@@ -785,12 +811,26 @@ func TestBuildGraph(t *testing.T) {
 							client.ObjectKeyFromObject(gw1.Source),
 							"listener-443-2",
 						): {"fizz.example.org"},
+					},
+				},
+				SectionName: &gw1.Source.Spec.Listeners[2].Name,
+			},
+			{
+				Idx: 0,
+				Gateway: &ParentRefGateway{
+					NamespacedName:      client.ObjectKeyFromObject(gw1.Source),
+					EffectiveNginxProxy: np1Effective,
+				},
+				Attachment: &ParentRefAttachmentStatus{
+					Attached: true,
+					AcceptedHostnames: map[string][]string{
 						CreateGatewayListenerKey(
 							client.ObjectKeyFromObject(gw1.Source),
 							"listener-8443",
 						): {"fizz.example.org"},
 					},
 				},
+				SectionName: &gw1.Source.Spec.Listeners[3].Name,
 			},
 		},
 		Spec: L4RouteSpec{
@@ -814,6 +854,45 @@ func TestBuildGraph(t *testing.T) {
 		Attachable: true,
 		Source:     tr2,
 		ParentRefs: []ParentRef{
+			{
+				Idx: 0,
+				Gateway: &ParentRefGateway{
+					NamespacedName:      client.ObjectKeyFromObject(gw1.Source),
+					EffectiveNginxProxy: np1Effective,
+				},
+				Attachment: &ParentRefAttachmentStatus{
+					Attached:          false,
+					AcceptedHostnames: map[string][]string{},
+					FailedConditions:  []conditions.Condition{conditions.NewRouteNotAllowedByListeners()},
+				},
+				SectionName: &gw1.Source.Spec.Listeners[0].Name,
+			},
+			{
+				Idx: 0,
+				Gateway: &ParentRefGateway{
+					NamespacedName:      client.ObjectKeyFromObject(gw1.Source),
+					EffectiveNginxProxy: np1Effective,
+				},
+				Attachment: &ParentRefAttachmentStatus{
+					AcceptedHostnames: map[string][]string{},
+					Attached:          false,
+					FailedConditions:  []conditions.Condition{conditions.NewRouteNotAllowedByListeners()},
+				},
+				SectionName: &gw1.Source.Spec.Listeners[1].Name,
+			},
+			{
+				Idx: 0,
+				Gateway: &ParentRefGateway{
+					NamespacedName:      client.ObjectKeyFromObject(gw1.Source),
+					EffectiveNginxProxy: np1Effective,
+				},
+				Attachment: &ParentRefAttachmentStatus{
+					Attached:          false,
+					AcceptedHostnames: map[string][]string{},
+					FailedConditions:  []conditions.Condition{conditions.NewRouteHostnameConflict()},
+				},
+				SectionName: &gw1.Source.Spec.Listeners[2].Name,
+			},
 			{
 				Idx: 0,
 				Gateway: &ParentRefGateway{
@@ -825,6 +904,7 @@ func TestBuildGraph(t *testing.T) {
 					AcceptedHostnames: map[string][]string{},
 					FailedConditions:  []conditions.Condition{conditions.NewRouteHostnameConflict()},
 				},
+				SectionName: &gw1.Source.Spec.Listeners[3].Name,
 			},
 		},
 		Spec: L4RouteSpec{
diff --git a/internal/controller/state/graph/policies_test.go b/internal/controller/state/graph/policies_test.go
index 6d477ea8..7df4a9d4 100644
--- a/internal/controller/state/graph/policies_test.go
+++ b/internal/controller/state/graph/policies_test.go
@@ -1126,6 +1126,7 @@ func TestProcessPolicies_RouteOverlap(t *testing.T) {
 	policyGVK := schema.GroupVersionKind{Group: "Group", Version: "Version", Kind: "MyPolicy"}
 	pol1, pol1Key := createTestPolicyAndKey(policyGVK, "pol1", hrRefCoffee)
 	pol2, pol2Key := createTestPolicyAndKey(policyGVK, "pol2", hrRefCoffee, hrRefCoffeeTea)
+	pol3, pol3Key := createTestPolicyAndKey(policyGVK, "pol3", hrRefCoffeeTea)
 
 	tests := []struct {
 		validator     validation.PolicyValidator
@@ -1153,6 +1154,25 @@ func TestProcessPolicies_RouteOverlap(t *testing.T) {
 			},
 			valid: true,
 		},
+		{
+			name:      "no overlap two policies",
+			validator: &policiesfakes.FakeValidator{},
+			policies: map[PolicyKey]policies.Policy{
+				pol1Key: pol1,
+				pol3Key: pol3,
+			},
+			routes: map[RouteKey]*L7Route{
+				{
+					RouteType:      RouteTypeHTTP,
+					NamespacedName: types.NamespacedName{Namespace: testNs, Name: "hr-coffee"},
+				}: createTestRouteWithPaths("hr-coffee", "/coffee"),
+				{
+					RouteType:      RouteTypeHTTP,
+					NamespacedName: types.NamespacedName{Namespace: testNs, Name: "hr-coffee-tea"},
+				}: createTestRouteWithPaths("hr-coffee-tea", "/coffee-tea"),
+			},
+			valid: true,
+		},
 		{
 			name:      "policy references route that overlaps a non-referenced route",
 			validator: &policiesfakes.FakeValidator{},
@@ -1256,7 +1276,7 @@ func TestProcessPolicies_RouteOverlap(t *testing.T) {
 			g := NewWithT(t)
 
 			processed := processPolicies(test.policies, test.validator, test.routes, nil, gateways)
-			g.Expect(processed).To(HaveLen(1))
+			g.Expect(processed).To(HaveLen(len(test.policies)))
 
 			for _, pol := range processed {
 				g.Expect(pol.Valid).To(Equal(test.valid))
diff --git a/internal/controller/state/graph/route_common_test.go b/internal/controller/state/graph/route_common_test.go
index 8acf8c00..4b4fd1c2 100644
--- a/internal/controller/state/graph/route_common_test.go
+++ b/internal/controller/state/graph/route_common_test.go
@@ -25,6 +25,7 @@ func TestBuildSectionNameRefs(t *testing.T) {
 
 	gwNsName1 := types.NamespacedName{Namespace: routeNamespace, Name: "gateway-1"}
 	gwNsName2 := types.NamespacedName{Namespace: routeNamespace, Name: "gateway-2"}
+	gwNsName3 := types.NamespacedName{Namespace: routeNamespace, Name: "gateway-3"}
 
 	parentRefs := []gatewayv1.ParentReference{
 		{
@@ -51,6 +52,10 @@ func TestBuildSectionNameRefs(t *testing.T) {
 			Name:        gatewayv1.ObjectName("some-other-gateway"),
 			SectionName: helpers.GetPointer[gatewayv1.SectionName]("same-name"),
 		},
+		{
+			Name:        gatewayv1.ObjectName(gwNsName3.Name),
+			SectionName: nil,
+		},
 	}
 
 	gws := map[types.NamespacedName]*Gateway{
@@ -70,6 +75,26 @@ func TestBuildSectionNameRefs(t *testing.T) {
 				},
 			},
 		},
+		gwNsName3: {
+			Listeners: []*Listener{
+				{
+					Source: gatewayv1.Listener{
+						Name: "http",
+					},
+				},
+				{
+					Source: gatewayv1.Listener{
+						Name: "https",
+					},
+				},
+			},
+			Source: &gatewayv1.Gateway{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      gwNsName3.Name,
+					Namespace: gwNsName3.Namespace,
+				},
+			},
+		},
 	}
 
 	expected := []ParentRef{
@@ -93,6 +118,16 @@ func TestBuildSectionNameRefs(t *testing.T) {
 			Gateway:     CreateParentRefGateway(gws[gwNsName2]),
 			SectionName: parentRefs[4].SectionName,
 		},
+		{
+			Idx:         6,
+			Gateway:     CreateParentRefGateway(gws[gwNsName3]),
+			SectionName: helpers.GetPointer[gatewayv1.SectionName]("http"),
+		},
+		{
+			Idx:         6,
+			Gateway:     CreateParentRefGateway(gws[gwNsName3]),
+			SectionName: helpers.GetPointer[gatewayv1.SectionName]("https"),
+		},
 	}
 
 	tests := []struct {
@@ -124,16 +159,16 @@ func TestBuildSectionNameRefs(t *testing.T) {
 		{
 			parentRefs: []gatewayv1.ParentReference{
 				{
-					Name:        gatewayv1.ObjectName(gwNsName1.Name),
-					SectionName: nil,
+					Name:        gatewayv1.ObjectName(gwNsName3.Name),
+					SectionName: helpers.GetPointer[gatewayv1.SectionName]("http"),
 				},
 				{
-					Name:        gatewayv1.ObjectName(gwNsName1.Name),
+					Name:        gatewayv1.ObjectName(gwNsName3.Name),
 					SectionName: nil,
 				},
 			},
-			name:          "nil sectionNames",
-			expectedError: errors.New("duplicate section name \"\" for Gateway test/gateway-1"),
+			name:          "duplicate sectionNames when one parentRef has no sectionName",
+			expectedError: errors.New("duplicate section name \"http\" for Gateway test/gateway-3"),
 		},
 	}
 
diff --git a/internal/controller/status/prepare_requests_test.go b/internal/controller/status/prepare_requests_test.go
index 81f29294..2480423d 100644
--- a/internal/controller/status/prepare_requests_test.go
+++ b/internal/controller/status/prepare_requests_test.go
@@ -72,6 +72,21 @@ var (
 			{
 				SectionName: helpers.GetPointer[v1.SectionName]("listener-80-3"),
 			},
+			{
+				SectionName: helpers.GetPointer[v1.SectionName]("listener-443-1"),
+			},
+			{
+				SectionName: helpers.GetPointer[v1.SectionName]("listener-443-2"),
+			},
+			{
+				SectionName: helpers.GetPointer[v1.SectionName]("listener-443-3"),
+			},
+			{
+				SectionName: helpers.GetPointer[v1.SectionName]("listener-8080-1"),
+			},
+			{
+				SectionName: helpers.GetPointer[v1.SectionName]("listener-8080-2"),
+			},
 		},
 	}
 
@@ -110,6 +125,50 @@ var (
 				FailedConditions: []conditions.Condition{invalidAttachmentCondition},
 			},
 		},
+		{
+			Idx:         3,
+			Gateway:     &graph.ParentRefGateway{NamespacedName: gwNsName},
+			SectionName: commonRouteSpecValid.ParentRefs[3].SectionName,
+			Attachment: &graph.ParentRefAttachmentStatus{
+				Attached:         false,
+				FailedConditions: []conditions.Condition{invalidAttachmentCondition},
+			},
+		},
+		{
+			Idx:         3,
+			Gateway:     &graph.ParentRefGateway{NamespacedName: gwNsName},
+			SectionName: commonRouteSpecValid.ParentRefs[4].SectionName,
+			Attachment: &graph.ParentRefAttachmentStatus{
+				Attached: true,
+			},
+		},
+		{
+			Idx:         3,
+			Gateway:     &graph.ParentRefGateway{NamespacedName: gwNsName},
+			SectionName: commonRouteSpecValid.ParentRefs[5].SectionName,
+			Attachment: &graph.ParentRefAttachmentStatus{
+				Attached:         true,
+				FailedConditions: []conditions.Condition{invalidAttachmentCondition},
+			},
+		},
+		{
+			Idx:         4,
+			Gateway:     &graph.ParentRefGateway{NamespacedName: gwNsName},
+			SectionName: commonRouteSpecValid.ParentRefs[6].SectionName,
+			Attachment: &graph.ParentRefAttachmentStatus{
+				Attached:         false,
+				FailedConditions: []conditions.Condition{invalidAttachmentCondition},
+			},
+		},
+		{
+			Idx:         4,
+			Gateway:     &graph.ParentRefGateway{NamespacedName: gwNsName},
+			SectionName: commonRouteSpecValid.ParentRefs[7].SectionName,
+			Attachment: &graph.ParentRefAttachmentStatus{
+				Attached:         false,
+				FailedConditions: []conditions.Condition{invalidAttachmentCondition},
+			},
+		},
 	}
 
 	parentRefsInvalid = []graph.ParentRef{
@@ -213,6 +272,62 @@ var (
 					},
 				},
 			},
+			{
+				ParentRef: v1.ParentReference{
+					Namespace: helpers.GetPointer(v1.Namespace(gwNsName.Namespace)),
+					Name:      v1.ObjectName(gwNsName.Name),
+				},
+				ControllerName: gatewayCtlrName,
+				Conditions: []metav1.Condition{
+					{
+						Type:               string(v1.RouteConditionAccepted),
+						Status:             metav1.ConditionTrue,
+						ObservedGeneration: 3,
+						LastTransitionTime: transitionTime,
+						Reason:             string(v1.RouteReasonAccepted),
+						Message:            "The route is accepted",
+					},
+					{
+						Type:               string(v1.RouteConditionResolvedRefs),
+						Status:             metav1.ConditionTrue,
+						ObservedGeneration: 3,
+						LastTransitionTime: transitionTime,
+						Reason:             string(v1.RouteReasonResolvedRefs),
+						Message:            "All references are resolved",
+					},
+				},
+			},
+			{
+				ParentRef: v1.ParentReference{
+					Namespace: helpers.GetPointer(v1.Namespace(gwNsName.Namespace)),
+					Name:      v1.ObjectName(gwNsName.Name),
+				},
+				ControllerName: gatewayCtlrName,
+				Conditions: []metav1.Condition{
+					{
+						Type:               string(v1.RouteConditionAccepted),
+						Status:             metav1.ConditionTrue,
+						ObservedGeneration: 3,
+						LastTransitionTime: transitionTime,
+						Reason:             string(v1.RouteReasonAccepted),
+						Message:            "The route is accepted",
+					},
+					{
+						Type:               string(v1.RouteConditionResolvedRefs),
+						Status:             metav1.ConditionTrue,
+						ObservedGeneration: 3,
+						LastTransitionTime: transitionTime,
+						Reason:             string(v1.RouteReasonResolvedRefs),
+						Message:            "All references are resolved",
+					},
+					{
+						Type:               invalidAttachmentCondition.Type,
+						Status:             metav1.ConditionTrue,
+						ObservedGeneration: 3,
+						LastTransitionTime: transitionTime,
+					},
+				},
+			},
 		},
 	}