hashicorp/nomad · error
handle cannot be nil
Error message
handle cannot be nil
What it means
This error is returned by the Java driver's RecoverTask method when called with a nil *drivers.TaskHandle. RecoverTask is used after a Nomad client/agent restart to reattach to a running task's executor; without a valid handle there is nothing to recover. It is a defensive guard against programming errors in the driver manager.
Source
Thrown at drivers/java/driver.go:380
if err != nil {
// return no error, as it isn't an error to not find java, it just means we
// can't use it.
fp.Health = drivers.HealthStateUndetected
fp.HealthDescription = ""
return fp
}
fp.Attributes[driverAttr] = pstructs.NewBoolAttribute(true)
fp.Attributes[driverVersionAttr] = pstructs.NewStringAttribute(version)
fp.Attributes["driver.java.runtime"] = pstructs.NewStringAttribute(jdkJRE)
fp.Attributes["driver.java.vm"] = pstructs.NewStringAttribute(vm)
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.Debug("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 driver manager restores and passes a valid TaskHandle from client state
- Fix the caller so nil handles are skipped or re-created before RecoverTask
- If writing custom tooling, check the handle for nil before calling RecoverTask
- Restart the Nomad client to re-run recovery with intact state; report a bug if it persists
Example fix
// before
err := driver.RecoverTask(nil)
// after
if handle != nil {
err = driver.RecoverTask(handle)
} Defensive patterns
Strategy: type-guard
Validate before calling
if handle == nil {
return errors.New("cannot recover: task handle is nil")
} Type guard
func validHandle(h *drivers.TaskHandle) bool { return h != nil && h.Config.ID != "" } Try / catch
if err := driver.RecoverTask(handle); err != nil {
if strings.Contains(err.Error(), "handle cannot be nil") {
// skip or recreate handle before retrying
}
} Prevention
- Never call driver APIs directly with nil handles; let the driver manager manage recovery
- Persist and reload handles from client state correctly
- Add unit tests for recovery paths with nil/empty handles
When it happens
Trigger: The Nomad client's driver manager calls d.RecoverTask(nil), typically due to a bug in handle restoration from the client state store or a nil handle passed during plugin recovery.
Common situations: Post-restore bugs where the handle was not persisted or failed to deserialize to a non-nil value; custom code or plugins invoking the driver API directly with a nil 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
- must pass non-nil job
- missing node pool
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/5988a61f121eb58f.
Report an issue: GitHub.