hashicorp/nomad · error
error: handle cannot be nil
Error message
error: handle cannot be nil
What it means
Returned by the QEMU driver's RecoverTask when called with a nil task handle; recovery cannot restore state for a missing/stale handle, indicating the task ID is unknown after a restart.
Source
Thrown at drivers/qemu/driver.go:288
matches := versionRegex.FindStringSubmatch(out)
if len(matches) != 2 {
fingerprint.Health = drivers.HealthStateUndetected
fingerprint.HealthDescription = fmt.Sprintf("Failed to parse qemu version from %v", out)
return fingerprint
}
currentQemuVersion := matches[1]
fingerprint.Attributes[driverAttr] = pstructs.NewBoolAttribute(true)
fingerprint.Attributes[driverVersionAttr] = pstructs.NewStringAttribute(currentQemuVersion)
fingerprint.Attributes[driverEmulatorsAttr] = pstructs.NewStringAttribute(strings.Join(emulators, ","))
return fingerprint
}
func (d *Driver) RecoverTask(handle *drivers.TaskHandle) error {
if handle == nil {
return fmt.Errorf("error: 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
}
var taskState TaskState
if err := handle.GetDriverState(&taskState); err != nil {
d.logger.Error("failed to decode taskConfig state from handle", "error", err, "task_id", handle.Config.ID)
return fmt.Errorf("failed to decode taskConfig state from handle: %v", err)
}
plugRC, err := pstructs.ReattachConfigToGoPlugin(taskState.ReattachConfig)View on GitHub (pinned to 482b49bf1a)
Solutions
- Ensure the caller obtains a valid *drivers.TaskHandle (via drivers.NewTaskHandle + Config) before calling RecoverTask.
- Add a nil check at the call site and skip/log instead of calling RecoverTask with nil.
- If handles come from persisted state, verify that state was successfully loaded before recovery.
Example fix
// before
err := d.RecoverTask(h)
// after
if h == nil {
return errors.New("no task handle to recover")
}
err := d.RecoverTask(h) Defensive patterns
Strategy: type-guard
Validate before calling
if handle == nil {
return errors.New("refusing to recover: task handle is nil")
} Type guard
func recoverable(h *drivers.TaskHandle) bool { return h != nil && h.Config != nil && h.Config.ID != "" } Try / catch
if !recoverable(h) {
return errors.New("no valid handle to recover")
}
err := d.RecoverTask(h) Prevention
- Never pass a nil handle into RecoverTask; obtain it from loaded client state.
- Assert handles are populated (Config.ID set) before recovery attempts.
When it happens
Trigger: Calling Driver.RecoverTask(nil), e.g. when a caller's handle lookup failed but nil was passed through instead of being checked.
Common situations: Client plugin re-attachment logic passing an unpopulated handle after a failed GetTaskHandle; tests invoking RecoverTask without constructing a handle.
Related errors
- failed to decode taskConfig state from handle: %v
- failed to build ReattachConfig from taskConfig state: %v
- failed to reattach to executor: %v
- handle cannot be nil
- failed to decode taskConfig state from handle: %v
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/768954d620a43c6f.
Report an issue: GitHub.