hashicorp/nomad · error

service.port must be set for mesh gateway service

Error message

service.port must be set for mesh gateway service

What it means

A Consul mesh gateway service requires a service port label because that port is used to publish the mesh gateway's WAN address. Nomad's groupConnectHook mutator returns this error when a connect gateway of kind mesh-gateway has an empty service.PortLabel.

Source

Thrown at nomad/job_endpoint_hook_connect.go:363

			service.Connect.Gateway.Proxy = gatewayProxy(service.Connect.Gateway, netMode)

			// Inject a port whether bridge or host network (if not already set).
			// This port is accessed by the magic of Connect plumbing so it seems
			// reasonable to keep the magic alive here.
			if service.Connect.IsTerminating() && service.PortLabel == "" {
				// Inject a dynamic port for the terminating gateway.
				portLabel := envoy.PortLabel(structs.ConnectTerminatingPrefix, service.Name, "")
				service.PortLabel = portLabel
				injectPort(g, portLabel)
			}

			// A mesh Gateway will need 2 ports (lan and wan).
			if service.Connect.IsMesh() {

				// service port is used for mesh gateway wan address - it should
				// come from a configured host_network to make sense
				if service.PortLabel == "" {
					return errors.New("service.port must be set for mesh gateway service")
				}

				// Inject a dynamic port for mesh gateway LAN address.
				lanPortLabel := envoy.PortLabel(structs.ConnectMeshPrefix, service.Name, "lan")
				injectPort(g, lanPortLabel)
			}

			// inject the gateway task only if it does not yet already exist
			if !hasGatewayTaskForService(g, service.Name) {
				prefix := service.Connect.Gateway.Prefix()

				// detect whether the group is in host networking mode, which will
				// require tweaking the default gateway task config
				netHost := netMode == "host"
				customizedTLS := service.Connect.IsCustomizedTLS()

				task := newConnectGatewayTask(prefix, service.Name,
					service.GetConsulClusterName(g), groupConnectGuessTaskDriver(g), netHost, customizedTLS)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set `port` on the service that has the mesh gateway block (e.g. pointing to a port on a configured host_network).
  2. Use a port defined with host_network so the WAN address is meaningful.
  3. Re-submit the job after adding the port label.

Example fix

// before
service {
  name = "mesh-gw"
  connect {
    gateway {
      mesh {}
    }
  }
}

// after
service {
  name = "mesh-gw"
  port = "8443"
  connect {
    gateway {
      mesh {}
    }
  }
}
Defensive patterns

Strategy: validation

Validate before calling

for _, svc := range group.Services {
  if svc.Connect != nil && svc.Connect.IsMesh() && svc.PortLabel == "" {
    return fmt.Errorf("service %q: mesh gateway requires a port", svc.Name)
  }
}

Prevention

When it happens

Trigger: Defining a `gateway { mesh { ... } }` in a connect block without setting the service's `port` field, then submitting/mutating the job through groupConnectHook.

Common situations: Configuring Consul ingress/terminating gateways works without a service port, so users assume mesh gateways do too; forgetting that mesh gateways additionally need the wan-facing port label.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/aea61ea17b0472fb. Report an issue: GitHub.