{"record":{"id":"ad02cf2f458989c2","repo":"hashicorp/nomad","slug":"handle-cannot-be-nil-ad02cf","errorCode":null,"errorMessage":"handle cannot be nil","messagePattern":"handle cannot be nil","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/mock/driver.go","lineNumber":361,"sourceCode":"\tif !d.shutdownFingerprintTime.IsZero() && time.Now().After(d.shutdownFingerprintTime) {\n\t\thealth = drivers.HealthStateUndetected\n\t\tdesc = \"disabled\"\n\t} else {\n\t\thealth = drivers.HealthStateHealthy\n\t\tattrs[\"driver.mock_driver\"] = pstructs.NewBoolAttribute(true)\n\t\tdesc = drivers.DriverHealthy\n\t}\n\n\treturn &drivers.Fingerprint{\n\t\tAttributes:        attrs,\n\t\tHealth:            health,\n\t\tHealthDescription: desc,\n\t}\n}\n\nfunc (d *Driver) RecoverTask(handle *drivers.TaskHandle) error {\n\tif handle == nil {\n\t\treturn fmt.Errorf(\"handle cannot be nil\")\n\t}\n\n\t// Unmarshall the driver state and create a new handle\n\tvar taskState MockTaskState\n\tif err := handle.GetDriverState(&taskState); err != nil {\n\t\td.logger.Error(\"failed to decode task state from handle\", \"error\", err, \"task_id\", handle.Config.ID)\n\t\treturn fmt.Errorf(\"failed to decode task state from handle: %v\", err)\n\t}\n\n\ttaskState.Command.parseDurations()\n\tif taskState.ExecCommand != nil {\n\t\ttaskState.ExecCommand.parseDurations()\n\t}\n\n\t// Correct the run_for time based on how long it has already been running\n\tnow := time.Now()\n\tif !taskState.StartedAt.IsZero() {\n\t\ttaskState.Command.runForDuration = taskState.Command.runForDuration - now.Sub(taskState.StartedAt)","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/drivers/mock/driver.go#L343-L379","documentation":"The mock driver's RecoverTask restores a task from a drivers.TaskHandle persisted across agent restarts. A nil handle carries no state to restore, so the driver rejects the call immediately. This is a defensive check against a programming error in the caller (usually the client/runtime), not an environment problem.","triggerScenarios":"Calling Driver.RecoverTask(nil) on drivers/mock_driver, e.g. during plugin reattach/restore when the handle was never created or was lost and not re-checked for nil.","commonSituations":"Custom Nomad forks or test harnesses restoring drivers after agent restart with a corrupt/empty task store; unit tests invoking RecoverTask directly with a nil handle.","solutions":["Ensure the caller obtains the handle from the driver's task store/persisted state and only calls RecoverTask with a non-nil *drivers.TaskHandle.","Guard the call site: skip or log when handle == nil before invoking RecoverTask.","If this happens during agent restore, check that task state was correctly persisted and restored upstream."],"exampleFix":"// before\nif err := d.RecoverTask(handles[i]); err != nil {...}\n// after\nif handles[i] == nil {\n    continue // nothing to recover\n}\nif err := d.RecoverTask(handles[i]); err != nil {...}","handlingStrategy":"validation","validationCode":"if handle == nil {\n    return errors.New(\"cannot recover task: handle is nil\")\n}\nerr := driver.RecoverTask(handle)","typeGuard":"func recoverable(h *drivers.TaskHandle) bool { return h != nil && h.Config != nil }","tryCatchPattern":"if err := d.RecoverTask(h); err != nil {\n    if err.Error() == \"handle cannot be nil\" {\n        return errors.New(\"caller bug: nil handle passed to RecoverTask\")\n    }\n    return err\n}","preventionTips":["Only pass handles obtained from the driver or a properly restored task store.","Nil-check handles at restore/reconnect boundaries before calling RecoverTask.","Cover recovery paths with unit tests that exercise nil/empty handle inputs."],"tags":["nomad","mock-driver","nil-argument","task-recovery"],"backgroundTag":"nil-argument","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"}