{"record":{"id":"dbc52ae762f8cd3c","repo":"hashicorp/nomad","slug":"unexpected-state-s","errorCode":null,"errorMessage":"unexpected state %s","messagePattern":"unexpected state (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/allocrunner/tasklifecycle/coordinator.go","lineNumber":210,"sourceCode":"\tcase coordinatorStatePoststart:\n\t\tif !c.isPoststartDone(states) {\n\t\t\treturn coordinatorStatePoststart\n\t\t}\n\t\treturn coordinatorStateWaitAlloc\n\n\tcase coordinatorStateWaitAlloc:\n\t\tif !c.isAllocDone(states) {\n\t\t\treturn coordinatorStateWaitAlloc\n\t\t}\n\t\treturn coordinatorStatePoststop\n\n\tcase coordinatorStatePoststop:\n\t\treturn coordinatorStatePoststop\n\t}\n\n\t// If the code reaches here it's a programming error, since the switch\n\t// statement should cover all possible states and return the next state.\n\tpanic(fmt.Sprintf(\"unexpected state %s\", c.currentState))\n}\n\n// enterStateLocked updates the current state of the Coordinator FSM and\n// executes any action necessary for the state transition.\n// The currentStateLock must be held before calling this method.\nfunc (c *Coordinator) enterStateLocked(state coordinatorState) {\n\tc.logger.Trace(\"state transition\", \"from\", c.currentState, \"to\", state)\n\n\tswitch state {\n\tcase coordinatorStateInit:\n\t\tc.block(lifecycleStagePrestartEphemeral)\n\t\tc.block(lifecycleStagePrestartSidecar)\n\t\tc.block(lifecycleStageMain)\n\t\tc.block(lifecycleStagePoststartEphemeral)\n\t\tc.block(lifecycleStagePoststartSidecar)\n\t\tc.block(lifecycleStagePoststop)\n\n\tcase coordinatorStatePrestart:","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/allocrunner/tasklifecycle/coordinator.go#L192-L228","documentation":"The task lifecycle Coordinator is a finite state machine (FSM); nextStateLocked computes the next state from currentState via an exhaustive switch. This panic fires when currentState holds a value outside the known state set — by design unreachable in correct code, so it signals a corrupted or uninitialized FSM state rather than a user-facing failure.","triggerScenarios":"TaskStateUpdated -> nextStateLocked is called while c.currentState is a zero-value/uninitialized coordinatorState or one added to the enum without a corresponding case in the switch.","commonSituations":"A developer adds a new coordinatorState constant but forgets to add a case in nextStateLocked; state struct initialized without going through NewCoordinator; memory corruption or unsafe state writes bypassing currentStateLock.","solutions":["Add a case in nextStateLocked for the missing coordinatorState value","Check the state value printed in the panic message against the coordinatorState enum to identify the unknown state","Ensure Coordinator instances are created via the constructor so currentState is always initialized","File/inspect a bug report with the state string from the panic — this should never happen in production"],"exampleFix":"// before\nswitch c.currentState {\ncase coordinatorStateInit:\n  ...\n}\n// after\nswitch c.currentState {\ncase coordinatorStateInit:\n  ...\ncase coordinatorStateNewState:\n  return coordinatorStateNewState // newly added state now handled\n}","handlingStrategy":"validation","validationCode":"// before triggering transitions\nfunc validState(s coordinatorState) bool {\n    switch s {\n    case coordinatorStateInit, coordinatorStatePrestart,\n        coordinatorStateRunning, coordinatorStatePoststop:\n        return true\n    }\n    return false\n}\nif !validState(c.currentState) { return }\n","typeGuard":null,"tryCatchPattern":"// Go: recover around the coordinator call\ndefer func() {\n    if r := recover(); r != nil {\n        logger.Error(\"coordinator FSM invalid state\", \"panic\", r, \"state\", fmt.Sprint(c.currentState))\n    }\n}()","preventionTips":["Always add a switch case in nextStateLocked when adding a new coordinatorState","Initialize Coordinator only through its constructor","Keep the FSM exhaustive: enable exhaustive-switch linting"],"tags":["fsm","state-machine","programming-error","panic"],"backgroundTag":"fsm-invalid-state-transition","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}