hashicorp/nomad · error
handle cannot be nil
Error message
handle cannot be nil
What it means
Defensive guard in exec Driver.RecoverTask: a nil *drivers.TaskHandle was passed, which is a programming error by the plugin caller (a real recovery always has a handle); no handle means no task ID to look up.
Source
Thrown at drivers/exec/driver.go:405
d.setFingerprintFailure()
return fp
}
if cgroupslib.GetMode() == cgroupslib.OFF {
fp.Health = drivers.HealthStateUnhealthy
fp.HealthDescription = drivers.NoCgroupMountMessage
d.setFingerprintFailure()
return fp
}
fp.Attributes["driver.exec"] = pstructs.NewBoolAttribute(true)
d.setFingerprintSuccess()
return fp
}
func (d *Driver) RecoverTask(handle *drivers.TaskHandle) error {
if handle == nil {
return fmt.Errorf("handle cannot be nil")
}
// If already attached to handle there's nothing to recover.
if _, ok := d.tasks.Get(handle.Config.ID); ok {
d.logger.Trace("nothing to recover; task already exists",
"task_id", handle.Config.ID,
"task_name", handle.Config.Name,
)
return nil
}
// Handle doesn't already exist, try to reattach
var taskState TaskState
if err := handle.GetDriverState(&taskState); err != nil {
d.logger.Error("failed to decode task state from handle", "error", err, "task_id", handle.Config.ID)
return fmt.Errorf("failed to decode task state from handle: %v", err)
}
View on GitHub (pinned to 482b49bf1a)
Solutions
- Ensure RecoverTask is only called with a valid handle from drivers.TaskRegistry or StartTask output
- Guard the call site with a nil check before invoking
- Fix handle construction/serialization upstream so nil handles aren't propagated
Example fix
// before
if err := driver.RecoverTask(nil); err != nil { ... }
// after
if handle == nil {
return fmt.Errorf("no handle to recover")
}
if err := driver.RecoverTask(handle); err != nil { ... } Defensive patterns
Strategy: type-guard
Validate before calling
if handle == nil {
return errors.New("refusing to recover: nil handle")
} Type guard
func hasHandle(h *drivers.TaskHandle) bool {
return h != nil && h.Config != nil && h.Config.ID != ""
} Try / catch
if !hasHandle(handle) {
return fmt.Errorf("skip recovery: no valid handle")
}
if err := driver.RecoverTask(handle); err != nil {
return fmt.Errorf("recover failed: %w", err)
} Prevention
- Only pass handles obtained from the task registry or StartTask
- Never persist/replay raw handle pointers across process boundaries
- Add nil assertions in restore code paths
When it happens
Trigger: Calling Driver.RecoverTask(nil), typically from host-side task restoration code paths where a handle failed to deserialize or was not produced by StartTask.
Common situations: Plugin/host integration bugs; custom code paths or tests invoking RecoverTask without a handle; restore logic after agent restart with corrupted handle data.
Related errors
- cannot destroy running task
- default_pid_mode must be %q or %q, got %q
- default_ipc_mode must be %q or %q, got %q
- allow_caps configured with capabilities not supported by sys
- pid_mode must be %q or %q, got %q
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/892dbec7dea3d6b7.
Report an issue: GitHub.