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

  1. Ensure the driver manager restores and passes a valid TaskHandle from client state
  2. Fix the caller so nil handles are skipped or re-created before RecoverTask
  3. If writing custom tooling, check the handle for nil before calling RecoverTask
  4. 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

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


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/5988a61f121eb58f. Report an issue: GitHub.