{"record":{"id":"876cecb1d064bf28","repo":"hashicorp/nomad","slug":"failed-to-attach-to-exec-v","errorCode":null,"errorMessage":"failed to attach to exec: %v","messagePattern":"failed to attach to exec: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/docker/driver.go","lineNumber":1986,"sourceCode":"\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tcase <-done:\n\t\t\t\treturn\n\t\t\tcase s, ok := <-opts.ResizeCh:\n\t\t\t\tif !ok {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t_, _ = client.ExecResize(d.ctx, exec.ID, mclient.ExecResizeOptions{\n\t\t\t\t\tHeight: uint(s.Height),\n\t\t\t\t\tWidth:  uint(s.Width),\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}()\n\n\tresp, err := client.ExecAttach(ctx, exec.ID, mclient.ExecAttachOptions{TTY: opts.Tty})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to attach to exec: %v\", err)\n\t}\n\tdefer func() {\n\t\topts.Stdin.Close() // close stdin\n\t\tresp.CloseWrite()  // close hijacked write connection\n\t\tresp.Close()       // close read connection\n\t}()\n\n\tgo func() {\n\t\tif !opts.Tty {\n\t\t\t_, _ = stdcopy.StdCopy(opts.Stdout, opts.Stderr, resp.Reader)\n\t\t} else {\n\t\t\t_, _ = io.Copy(opts.Stdout, resp.Reader)\n\t\t}\n\t}()\n\n\tgo func() {\n\t\t_, _ = io.Copy(resp.Conn, opts.Stdin)\n\t\t_ = resp.CloseWrite()","sourceCodeStart":1968,"sourceCodeEnd":2004,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/drivers/docker/driver.go#L1968-L2004","documentation":"After creating the exec instance, the driver hijacks the HTTP connection with `ExecAttach` to stream stdin/stdout/stderr. If attach fails, the exec object exists but no I/O stream could be established, and the driver wraps the error. Cleanup of the hijacked connection is deferred only on success.","triggerScenarios":"client.ExecAttach(ctx, exec.ID, mclient.ExecAttachOptions{...}) errors — network interruption to dockerd, exec ID invalid/expired, context deadline exceeded while upgrading the connection.","commonSituations":"Timeout expired before attach (large ctx from `timeout`); dockerd restarted between create and attach; proxy/load balancer between client and daemon blocking HTTP upgrade; exec cancelled by another caller.","solutions":["Increase the exec timeout passed to the driver so attach is not raced by ctx.Done().","Verify direct connectivity to dockerd (no proxy stripping HTTP upgrade headers).","Retry the whole exec operation; the exec ID from a failed attach is not reusable.","Check dockerd logs for exec attach failures around the timestamp."],"exampleFix":"// before\nctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)\n// after\nctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"stream, err := driver.ExecTaskStreaming(ctx, taskID, opts)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to attach to exec\") {\n        // retry with fresh exec and a larger timeout\n        ctx, cancel = context.WithTimeout(context.Background(), 60*time.Second)\n    }\n    return err\n}","preventionTips":["Use generous exec timeouts; attach must complete before ctx expires.","Avoid proxies/LBs between client and dockerd that break HTTP upgrade.","Retry exec operations as exec IDs are single-use."],"tags":["docker","exec","streaming","network"],"backgroundTag":"exec-attach-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"}