hashicorp/nomad · error
Unexpected task coordinator state %d
Error message
Unexpected task coordinator state %d
What it means
The String() method for coordinatorState translates the state enum to a human-readable name and panics when handed a value outside the known cases. This means the coordinator state variable was corrupted, a new state was added without updating String(), or an uninitialized/invalid state value flowed into logging or hook-label code.
Source
Thrown at client/allocrunner/tasklifecycle/coordinator.go:41
coordinatorStatePoststop
)
func (s coordinatorState) String() string {
switch s {
case coordinatorStateInit:
return "init"
case coordinatorStatePrestart:
return "prestart"
case coordinatorStateMain:
return "main"
case coordinatorStatePoststart:
return "poststart"
case coordinatorStateWaitAlloc:
return "wait_alloc"
case coordinatorStatePoststop:
return "poststart"
}
panic(fmt.Sprintf("Unexpected task coordinator state %d", s))
}
// lifecycleStage represents a lifecycle configuration used for task
// coordination.
//
// Not all possible combinations of hook X sidecar are defined, only the ones
// that are relevant for coordinating task initialization order. For example, a
// main task with sidecar set to `true` starts at the same time as a
// non-sidecar main task, so there is no need to treat them differently.
type lifecycleStage uint8
const (
// lifecycleStagePrestartEphemeral are tasks with the "prestart" hook and
// sidecar set to "false".
lifecycleStagePrestartEphemeral lifecycleStage = iota
// lifecycleStagePrestartSidecar are tasks with the "prestart" hook and
// sidecar set to "true".View on GitHub (pinned to 482b49bf1a)
Solutions
- Update to a library version where String() covers all coordinatorState values
- If you added a new state constant, add the corresponding case to String()
- Ensure coordinators are created via their constructor so state is initialized properly
- Avoid casting raw ints to coordinatorState; keep state assignment inside the coordinator
Example fix
// before
panic(fmt.Sprintf("Unexpected task coordinator state %d", s))
// after
default:
return fmt.Sprintf("unknown(%d)", s) // or return error instead of panicking Defensive patterns
Strategy: type-guard
Validate before calling
// Validate the state before formatting it
func validCoordinatorState(s coordinatorState) bool {
switch s {
case coordinatorStatePrestart, coordinatorStatePoststart,
coordinatorStateWaitAlloc, coordinatorStatePoststop:
return true
}
return false
} Type guard
func isKnownCoordinatorState(s coordinatorState) bool {
switch s {
case coordinatorStatePrestart, coordinatorStatePoststart,
coordinatorStateWaitAlloc, coordinatorStatePoststop:
return true
default:
return false
}
} Try / catch
// Go: recover when rendering state for logs
func stateLabel(s coordinatorState) (str string, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("bad coordinator state: %v", r)
}
}()
return s.String(), nil
} Prevention
- Always construct coordinators via their constructor so state is initialized
- Never cast raw ints to coordinatorState
- After adding a new state constant, update String() and all switches in the same change
- After library upgrades, run tests that exercise all lifecycle stages to surface missing-state cases
When it happens
Trigger: Calling String() (directly or via %s/%v formatting in logs and hook labels) with a coordinatorState value not covered by the switch — e.g., a zero-value/uninitialized coordinator, or a newly added coordinatorState constant missing a case after a library upgrade.
Common situations: Upgrading the library to a version that introduced a new coordinator state while custom code switches on state values; constructing a coordinator struct manually leaving the state field zero; custom logging that casts ints to coordinatorState.
Related errors
- unexpected state %s
- reconcile option is invalid
- not a valid task schedule state
- numa affinity must be one of none, prefer, or require
- Invalid change mode. Must be one of the following: noop, sig
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/c407cedd892c1fe6.
Report an issue: GitHub.