hashicorp/nomad · error

Service[%d] %s validation failed: %s

Error message

Service[%d] %s validation failed: %s

What it means

A service failed its own Service.Validate(); Nomad wraps the underlying validation error as 'Service[%d] %s validation failed: %s' and appends it to the job's multi-error, then stops processing that service to avoid nil-pointer access downstream.

Source

Thrown at nomad/structs/structs.go:7531

			// Track that we have seen this service provider
			providerSet.Insert(service.Provider)
		}
	}

	for i, service := range tg.Services {

		// Track that we have seen this service id
		id := unique{service.Name, "group", service.PortLabel}
		if !idSet.Insert(id) {
			// accumulate duplicates for a single error later on
			idDuplicateSet.Insert(id)
		}

		// Track that we have seen this service provider
		providerSet.Insert(service.Provider)

		if err := service.Validate(); err != nil {
			outer := fmt.Errorf("Service[%d] %s validation failed: %s", i, service.Name, err)
			mErr.Errors = append(mErr.Errors, outer)
			// we break here to avoid the risk of crashing on null-pointer
			// access in a later step, accepting that we might miss out on
			// error messages to provide the user.
			continue
		}
		if service.AddressMode == AddressModeDriver {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("service %q cannot use address_mode=\"driver\", only services defined in a \"task\" block can use this mode", service.Name))
		}

		for _, check := range service.Checks {
			if check.TaskName != "" {
				if check.AddressMode == AddressModeDriver {
					mErr.Errors = append(mErr.Errors, fmt.Errorf("Check %q invalid: cannot use address_mode=\"driver\", only checks defined in a \"task\" service block can use this mode", service.Name))
				}
				if !taskSet.Contains(check.TaskName) {
					mErr.Errors = append(mErr.Errors,
						fmt.Errorf("Check %s invalid: refers to non-existent task %s", check.Name, check.TaskName))

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Read the '%s' suffix of the message for the underlying service.Validate error and fix that field.
  2. Run nomad job validate to see the full wrapped error locally.
  3. Compare the service stanza against the documented schema for your Nomad version.

Example fix

// before
service { name="web" address_mode="bogus" }
// after
service { name="web" address_mode="auto" port="http" }
Defensive patterns

Strategy: try-catch

Validate before calling

for i, svc := range services {
  if err := svc.Validate(); err != nil {
    return fmt.Errorf("Service[%d] %s: %w", i, svc.Name, err)
  }
}

Try / catch

mErr := job.Validate()
if mErr != nil {
  for _, e := range mErr.Errors {
    var verr error
    if errors.As(e, &verr) && strings.Contains(e.Error(), "validation failed") {
      log.Printf("service error: %v", verr)
    }
  }
}

Prevention

When it happens

Trigger: Any invalid service definition (bad address_mode, empty port label when required, invalid check config, invalid provider, etc.) inside a group or task services block; the wrapped inner error names the real cause.

Common situations: Typo'd address_mode values; missing port_label for Consul services; check intervals/expose config errors; upgrading Nomad and newly-invalidated service fields.

Related errors


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