Skip to content

"client_max_body_size" directive is duplicate for a ClientSettingsPolicy attached to an HTTPRoute with multiple rules #3763

@mattmichal

Description

@mattmichal

Describe the bug
Targeting a ClientSettingsPolicy having spec.body.maxSize to an HTTPRoute with multiple rules generates invalid config that cannot be applied to nginx.

"client_max_body_size" directive is duplicate in /etc/nginx/includes/ClientSettingsPolicy_myroute_httproute-client-settings.conf:2

The same policy, when attached to an HTTPRoute with a single rule or when attached to a Gateway, does not cause invalid config to be generated.

To Reproduce
Steps to reproduce the behavior:

  1. Create an HTTPRoute with a single rule.
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: mydomain
      namespace: default
    spec:
      hostnames:
        - mydomain.example.cloud
      parentRefs:
        - name: defaultgateway
          sectionName: https
      rules:
        # fallback for all other requests
        - backendRefs:
            - name: mybackend
              port: 80
          filters:
            - type: ExtensionRef
              extensionRef:
                group: gateway.nginx.org
                kind: SnippetsFilter
                name: proxy-timeouts
          sessionPersistence:
            sessionName: SESSIONID
            type: Cookie
  2. Create a ClientSettingsPolicy and specify spec.body.maxSize: 250m
    apiVersion: gateway.nginx.org/v1alpha1
    kind: ClientSettingsPolicy
    metadata:
      name: httproute-client-settings
      namespace: default
    spec:
      targetRef:
        group: gateway.networking.k8s.io
        kind: HTTPRoute
        name: mydomain
        # kind: Gateway
        # name: defaultgateway
      body:
        maxSize: "250m"
  3. Observe that agent is configured correctly.
  4. Reconfigure the HTTPRoute to contain multiple rules.
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: mydomain
      namespace: default
    spec:
      hostnames:
        - mydomain.example.cloud
      parentRefs:
        - name: defaultgateway
          sectionName: https
      rules:
        # match with more headers matches first
        # /rest path with Referer header matching regex -> goes to app
        - matches:
          - path:
              type: PathPrefix
              value: /rest
            headers:
              - name: Referer
                type: RegularExpression
                value: "(?i)(mydomain|myotherdomain).+\\.example\\.(cloud|com)"
          backendRefs:
            - name: mybackend
              port: 80
          filters:
            - type: ExtensionRef
              extensionRef:
                group: gateway.nginx.org
                kind: SnippetsFilter
                name: proxy-timeouts
          sessionPersistence:
            sessionName: SESSIONID
            type: Cookie
        # /rest path with any other Referer header -> goes to api
        - matches:
            - path:
                type: PathPrefix
                value: /rest
          backendRefs:
            - name: mybackend-api
              port: 80
          filters:
            - type: ExtensionRef
              extensionRef:
                group: gateway.nginx.org
                kind: SnippetsFilter
                name: proxy-timeouts
          sessionPersistence:
            sessionName: SESSIONID
            type: Cookie
        # fallback for all other requests
        - backendRefs:
            - name: mybackend
              port: 80
          filters:
            - type: ExtensionRef
              extensionRef:
                group: gateway.nginx.org
                kind: SnippetsFilter
                name: proxy-timeouts
          sessionPersistence:
            sessionName: SESSIONID
            type: Cookie
  5. Observe that invalid configuration is generated and routing fails.

Expected behavior
When attaching a ClientSettingsPolicy to an HTTPRoute, valid configuration should always be generated, even if multiple rules are present.

Your environment

  • Version of the NGINX Gateway Fabric: 2.1.0
  • Version of Kubernetes: 1.31.3
  • Kubernetes platform: AKS
  • Details on how you expose the NGINX Gateway Fabric Pod: LoadBalancer Service with Azure annotations

Additional context

{"level":"debug","ts":"2025-08-19T19:07:02Z","logger":"nginxUpdater.fileService","msg":"Getting file for agent","file":"/etc/nginx/conf.d/http.conf"}
{"level":"debug","ts":"2025-08-19T19:07:02Z","logger":"nginxUpdater.fileService","msg":"Getting file for agent","file":"/etc/nginx/conf.d/matches.json"}
{"level":"error","ts":"2025-08-19T19:07:02Z","logger":"nginxUpdater.commandService","msg":"error sending request to agent","error":"msg: Config apply failed, rolling back config; error: failed validating config NGINX config test failed exit status 1: 2025/08/19 19:07:02 [emerg] 766#766: \"client_max_body_size\" directive is duplicate in /etc/nginx/includes/ClientSettingsPolicy_mydomain_httproute-client-settings.conf:2\nnginx: [emerg] \"client_max_body_size\" directive is duplicate in /etc/nginx/includes/ClientSettingsPolicy_mydomain_httproute-client-settings.conf:2\nnginx: configuration file /etc/nginx/nginx.conf test failed\n","stacktrace":"github.com/nginx/nginx-gateway-fabric/v2/internal/controller/nginx/agent.(*commandService).logAndSendErrorStatus\n\t/home/runner/work/nginx-gateway-fabric/nginx-gateway-fabric/internal/controller/nginx/agent/command.go:365\ngithub.com/nginx/nginx-gateway-fabric/v2/internal/controller/nginx/agent.(*commandService).setInitialConfig\n\t/home/runner/work/nginx-gateway-fabric/nginx-gateway-fabric/internal/controller/nginx/agent/command.go:322\ngithub.com/nginx/nginx-gateway-fabric/v2/internal/controller/nginx/agent.(*commandService).Subscribe\n\t/home/runner/work/nginx-gateway-fabric/nginx-gateway-fabric/internal/controller/nginx/agent/command.go:149\ngithub.com/nginx/agent/v3/api/grpc/mpi/v1._CommandService_Subscribe_Handler\n\tpkg/mod/github.com/nginx/agent/[email protected]/api/grpc/mpi/v1/command_grpc.pb.go:233\ngithub.com/nginx/nginx-gateway-fabric/v2/internal/controller/nginx/agent/grpc/interceptor.(*ContextSetter).Stream.ContextSetter.Stream.func1\n\t/home/runner/work/nginx-gateway-fabric/nginx-gateway-fabric/internal/controller/nginx/agent/grpc/interceptor/interceptor.go:65\ngoogle.golang.org/grpc.(*Server).processStreamingRPC\n\tpkg/mod/google.golang.org/[email protected]/server.go:1728\ngoogle.golang.org/grpc.(*Server).handleStream\n\tpkg/mod/google.golang.org/[email protected]/server.go:1845\ngoogle.golang.org/grpc.(*Server).serveStreams.func2.1\n\tpkg/mod/google.golang.org/[email protected]/server.go:1061"}
{"level":"error","ts":"2025-08-19T19:07:02Z","logger":"eventHandler","msg":"Failed to update NGINX configuration","error":"msg: Config apply failed, rolling back config; error: failed validating config NGINX config test failed exit status 1: 2025/08/19 19:07:02 [emerg] 766#766: \"client_max_body_size\" directive is duplicate in /etc/nginx/includes/ClientSettingsPolicy_mydomain_httproute-client-settings.conf:2\nnginx: [emerg] \"client_max_body_size\" directive is duplicate in /etc/nginx/includes/ClientSettingsPolicy_mydomain_httproute-client-settings.conf:2\nnginx: configuration file /etc/nginx/nginx.conf test failed\n","stacktrace":"github.com/nginx/nginx-gateway-fabric/v2/internal/controller.(*eventHandlerImpl).waitForStatusUpdates\n\t/home/runner/work/nginx-gateway-fabric/nginx-gateway-fabric/internal/controller/handler.go:262"}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    🆕 New

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions