hashicorp/nomad · error

Invalid HealthCheck: %q

Error message

Invalid HealthCheck: %q

What it means

MigrateStrategy.Validate accepts only "checks" (MigrateStrategyHealthChecks) or "states" (MigrateStrategyHealthStates) for HealthCheck; any other non-empty value hits the default case and is rejected with this formatted error quoting the invalid value. This ensures migration health evaluation has a known implementation.

Source

Thrown at nomad/structs/structs.go:6851

	}
}

func (m *MigrateStrategy) Validate() error {
	var mErr multierror.Error

	if m.MaxParallel < 0 {
		_ = multierror.Append(&mErr, fmt.Errorf("MaxParallel must be >= 0 but found %d", m.MaxParallel))
	}

	switch m.HealthCheck {
	case MigrateStrategyHealthChecks, MigrateStrategyHealthStates:
		// ok
	case "":
		if m.MaxParallel > 0 {
			_ = multierror.Append(&mErr, fmt.Errorf("Missing HealthCheck"))
		}
	default:
		_ = multierror.Append(&mErr, fmt.Errorf("Invalid HealthCheck: %q", m.HealthCheck))
	}

	if m.MinHealthyTime < 0 {
		_ = multierror.Append(&mErr, fmt.Errorf("MinHealthyTime is %s and must be >= 0", m.MinHealthyTime))
	}

	if m.HealthyDeadline < 0 {
		_ = multierror.Append(&mErr, fmt.Errorf("HealthyDeadline is %s and must be >= 0", m.HealthyDeadline))
	}

	if m.MinHealthyTime > m.HealthyDeadline {
		_ = multierror.Append(&mErr, fmt.Errorf("MinHealthyTime must be less than HealthyDeadline"))
	}

	return mErr.ErrorOrNil()
}

// TaskGroup is an atomic unit of placement. Each task group belongs to

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Change health_checks to exactly "checks" or "states" (lowercase).
  2. Check spelling and case; values are matched literally against the constants.
  3. Consult the Nomad update-block docs for allowed values.
  4. Run `nomad job validate` to confirm.

Example fix

// before
update {
  max_parallel  = 1
  health_checks = "health"
}
// after
update {
  max_parallel  = 1
  health_checks = "checks"
}
Defensive patterns

Strategy: validation

Validate before calling

var validHealthChecks = map[string]bool{"checks": true, "states": true}
func validHealthCheckValue(m *structs.MigrateStrategy) error {
	if m.HealthCheck != "" && !validHealthChecks[m.HealthCheck] {
		return fmt.Errorf("health_checks must be checks|states, got %q", m.HealthCheck)
	}
	return nil
}

Type guard

func isKnownHealthCheck(v string) bool {
	return v == structs.MigrateStrategyHealthChecks || v == structs.MigrateStrategyHealthStates || v == ""
}

Try / catch

if err := strategy.Validate(); err != nil {
	if strings.Contains(err.Error(), "Invalid HealthCheck") {
		// map/normalize the value to "checks" or "states" before resubmit
	}
}

Prevention

When it happens

Trigger: Submitting a job whose update block has health_checks set to a string other than "checks" or "states" (e.g. "health", "consul", or case-variant "Checks").

Common situations: Typos or wrong casing in HCL; copying terminology from Consul/other tools ('health_checks', 'grpc'); schema drift from generated configs.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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