hashicorp/nomad · error

Service %s kind must be one of consul service kind or empty

Error message

Service %s kind must be one of consul service kind or empty

What it means

validateConsulService checks that the service's `kind` field maps to a valid Consul service kind (typical, api-gateway, ingress-gateway, mesh-gateway, terminating-gateway) or is empty. Any other kind value is rejected because Consul would not accept the registration.

Source

Thrown at nomad/structs/services.go:883

			mErr.Errors = append(mErr.Errors, fmt.Errorf("Check %s invalid: tcp checks are not valid for Connect enabled services", c.Name))
			continue
		}

		// validate the consul check
		if err := c.validateConsul(); err != nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Check %s invalid: %v", c.Name, err))
		}
	}

	// validate the consul service kind
	switch api.ServiceKind(s.Kind) {
	case api.ServiceKindTypical,
		api.ServiceKindAPIGateway,
		api.ServiceKindIngressGateway,
		api.ServiceKindMeshGateway,
		api.ServiceKindTerminatingGateway:
	default:
		mErr.Errors = append(mErr.Errors, fmt.Errorf("Service %s kind must be one of consul service kind or empty", s.Name))
	}

	// check connect
	if s.Connect != nil {
		if err := s.Connect.Validate(); err != nil {
			mErr.Errors = append(mErr.Errors, err)
		}

		// if service is connect native, service task must be set (which may
		// happen implicitly in a job mutation if there is only one task)
		if s.Connect.IsNative() && len(s.TaskName) == 0 {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Service %s is Connect Native and requires setting the task", s.Name))
		}

		// if service is connect native a port must be set on the service or consul will reject it
		if s.Connect.IsNative() && s.PortLabel == "" {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Service %s is Connect Native and requires setting the port", s.Name))
		}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Remove the kind field (empty/typical is the default for normal services).
  2. Use one of the supported gateway kinds: "api-gateway", "ingress-gateway", "mesh-gateway", or "terminating-gateway".
  3. Fix the casing/spelling of the kind value.

Example fix

// before
service {
  name = "ingress"
  kind = "ingress_gateway"
  gateway { ingress { ... } }
}
// after
service {
  name = "ingress"
  kind = "ingress-gateway"
  gateway { ingress { ... } }
}
Defensive patterns

Strategy: validation

Validate before calling

var validKinds = map[string]bool{"": true, "typical": true, "api-gateway": true, "ingress-gateway": true, "mesh-gateway": true, "terminating-gateway": true}
if !validKinds[svc.Kind] { return fmt.Errorf("invalid kind %q", svc.Kind) }

Prevention

When it happens

Trigger: Setting kind = "connect-proxy", "terminating-gateway " (typo/whitespace), or any invented kind string on a service stanza with provider = "consul".

Common situations: Hand-copying Consul catalog kinds that Nomad services don't support; typos in gateway kind names; using kinds reserved for Consul's own registrations.

Related errors


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