{"record":{"id":"4748cd1aab607175","repo":"hashicorp/nomad","slug":"failed-to-decode-task-state-from-handle-v-4748cd","errorCode":null,"errorMessage":"failed to decode task state from handle: %v","messagePattern":"failed to decode task state from handle: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/mock/driver.go","lineNumber":368,"sourceCode":"\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)\n\n\t\tif taskState.ExecCommand != nil {\n\t\t\ttaskState.ExecCommand.runForDuration = taskState.ExecCommand.runForDuration - now.Sub(taskState.StartedAt)\n\t\t}\n\t}\n\n\t// Recreate the taskHandle. Because there's no real running process, we'll","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/drivers/mock/driver.go#L350-L386","documentation":"RecoverTask decodes the driver-specific state stored in the task handle into a MockTaskState via handle.GetDriverState. If the stored bytes cannot be unmarshaled (corrupt, empty, or written by an incompatible driver version), the driver logs and returns this wrapped error, refusing to restore the task.","triggerScenarios":"Calling RecoverTask with a handle whose driver state JSON does not match MockTaskState — e.g. state persisted by a different driver, truncated on disk, or schema changed between Nomad versions.","commonSituations":"Upgrading Nomad/mock driver across a schema change; hand-crafted handles in tests missing required fields; data-dir corruption after a crash; attaching the wrong driver's handle.","solutions":["Inspect handle state: it likely doesn't match MockTaskState; ensure the handle came from the mock driver's own PersistState.","If the state is corrupt after a crash or upgrade, let the task fail and restart it rather than recovering.","Keep driver and client versions consistent when rolling upgrades; clear stale data-dir state for the affected task.","In tests, build the handle by running the driver (StartTask) instead of hand-assembling driver state."],"exampleFix":"// before\nhandle := drivers.NewTaskHandle(\"mock\") // empty state\nplugin.RecoverTask(handle)\n// after\nhandle := drivers.NewTaskHandle(\"mock\")\nh := driver.StartTask(cfg)\n// recover using the handle produced by the driver itself","handlingStrategy":"try-catch","validationCode":"var probe MockTaskState\nif err := json.Unmarshal(rawDriverState, &probe); err != nil {\n    return fmt.Errorf(\"handle state is not valid MockTaskState; resubmit task instead of recovering\")\n}","typeGuard":"func isMockState(h *drivers.TaskHandle) bool {\n    var s MockTaskState\n    return h != nil && h.GetDriverState(&s) == nil\n}","tryCatchPattern":"if err := d.RecoverTask(h); err != nil {\n    if strings.Contains(err.Error(), \"failed to decode task state\") {\n        // state corrupt/incompatible: abandon recovery, restart task fresh\n        return d.StartTask(cfg)\n    }\n    return err\n}","preventionTips":["Recover only with handles the same driver version produced; avoid mixing versions across upgrades.","Generate handles in tests by running StartTask, not by hand-writing driver state.","Monitor data-dir integrity; treat decode failures as a signal to restart tasks fresh."],"tags":["nomad","mock-driver","deserialization","task-recovery","state-corruption"],"backgroundTag":"state-deserialization-failed","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"}