hashicorp/nomad · error

not a valid task schedule state

Error message

not a valid task schedule state

What it means

ScheduleStateApplyRequest.Validate accepts only TaskScheduleStateRun, ForceRun, SchedPause, and ForcePause. Any other value — including the zero value if it is not one of these — returns 'not a valid task schedule state', protecting the state machine from invalid transitions.

Source

Thrown at nomad/structs/node.go:442

	ScheduleState TaskScheduleState
}

func (r *ScheduleStateApplyRequest) Validate() error {
	if r.AllocID == "" {
		return errors.New("alloc id must be set")
	}

	if r.TaskName == "" {
		return errors.New("task name must be set")
	}

	switch r.ScheduleState {
	case TaskScheduleStateRun:
	case TaskScheduleStateForceRun:
	case TaskScheduleStateSchedPause:
	case TaskScheduleStateForcePause:
	default:
		return errors.New("not a valid task schedule state")
	}

	return nil
}

// ScheduleStateReadRequest is used to read the current pause state of a specific
// task running on a client.
type ScheduleStateReadRequest struct {
	QueryOptions // Client RPCs must use QueryOptions

	// NodeID is the node being targeted by this request (or the node receiving
	// this request if NodeID is empty).
	NodeID string

	// AllocID is the allocation being targeted by this request.
	AllocID string

	// TaskName is the name of the task being targeted by this request.

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Use the exported TaskScheduleState constants instead of raw integers
  2. Map API string inputs to valid constants with an explicit switch/mapping table
  3. Check client/server version parity if using a newly added state value
  4. Default to an explicit valid state (e.g. TaskScheduleStateRun) rather than the zero value

Example fix

// before
req := &structs.ScheduleStateApplyRequest{
  AllocID: allocID,
  TaskName: "redis",
  ScheduleState: structs.TaskScheduleState(7), // invalid
}

// after
req := &structs.ScheduleStateApplyRequest{
  AllocID: allocID,
  TaskName: "redis",
  ScheduleState: structs.TaskScheduleStateSchedPause,
}
Defensive patterns

Strategy: type-guard

Validate before calling

switch st {
case structs.TaskScheduleStateRun, structs.TaskScheduleStateForceRun,
	structs.TaskScheduleStateSchedPause, structs.TaskScheduleStateForcePause:
	// ok
default:
	return fmt.Errorf("invalid schedule state %d", st)
}

Type guard

func validTaskScheduleState(s structs.TaskScheduleState) bool {
	switch s {
	case structs.TaskScheduleStateRun,
		structs.TaskScheduleStateForceRun,
		structs.TaskScheduleStateSchedPause,
		structs.TaskScheduleStateForcePause:
		return true
	}
	return false
}

Prevention

When it happens

Trigger: Submitting a ScheduleStateApplyRequest with ScheduleState set to an unknown/zero integer not in {Run, ForceRun, SchedPause, ForcePause}; the switch default at node.go:442.

Common situations: Casting raw ints from external tooling into TaskScheduleState; API clients sending string states that decode to an unmapped numeric value; versions where a new state was added client-side but not on the server.

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/8627062398fca105. Report an issue: GitHub.