hashicorp/nomad · error

Check %s invalid: check requires a port but neither check no

Error message

Check %s invalid: check requires a port but neither check nor service %+q have a port

What it means

validateCheckPort fails when a service check RequiresPort() (e.g. tcp, http, grpc checks) but neither the check nor its parent service declares a port. Nomad cannot know which port to probe, so the service definition is rejected. Connect-based checks (which target the proxy) are exempt because they don't need an address.

Source

Thrown at nomad/structs/services.go:845

// identity name and service name.
func (s *Service) IdentityHandle(replace envReplacer) *WIHandle {
	if s.Identity != nil {
		wi := &WIHandle{
			IdentityName:       s.Identity.Name,
			WorkloadIdentifier: s.Name,
			WorkloadType:       WorkloadTypeService,
		}
		if replace != nil {
			wi.InterpolatedWorkloadIdentifier = replace(s.Name)
		}
		return wi
	}
	return nil
}

func (s *Service) validateCheckPort(c *ServiceCheck) error {
	if s.PortLabel == "" && c.PortLabel == "" && c.RequiresPort() {
		return fmt.Errorf("Check %s invalid: check requires a port but neither check nor service %+q have a port", c.Name, s.Name)
	}
	return nil
}

// validateConsulService performs validation on a service which is using the
// consul provider.
func (s *Service) validateConsulService(mErr *multierror.Error) {
	// check checks
	for _, c := range s.Checks {
		// validate the check port
		if err := s.validateCheckPort(c); err != nil {
			mErr.Errors = append(mErr.Errors, err)
			continue
		}

		// TCP checks against a Consul Connect enabled service are not supported
		// due to the service being bound to the loopback interface inside the
		// network namespace

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set `port` on the check stanza (e.g. port = "http").
  2. Set `port` on the parent service stanza so checks inherit it.
  3. If the check targets a Connect sidecar (http/grpc to the proxy), configure it so RequiresPort() is false rather than adding a port.

Example fix

// before
service {
  name = "web"
  check {
    type = "tcp"
    interval = "10s"
    timeout = "2s"
  }
}
// after
service {
  name = "web"
  port = "http"
  check {
    type = "tcp"
    interval = "10s"
    timeout = "2s"
  }
}
Defensive patterns

Strategy: validation

Validate before calling

func checkHasPort(svcPort string, c Check) error {
  needsPort := c.Type == "tcp" || c.Type == "http" || c.Type == "grpc"
  if needsPort && svcPort == "" && c.PortLabel == "" {
    return fmt.Errorf("check %q needs a port on the check or service", c.Name)
  }
  return nil
}

Prevention

When it happens

Trigger: A service with an empty port label containing a check of type tcp/http/grpc with no check-level port; or a check whose port refers to nothing because the service's port label is empty.

Common situations: Defining a health check on a service without assigning a port label; refactoring a service and dropping the port field; templated jobs where the port variable is empty.

Related errors


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