{"record":{"id":"d65bc796c8a69d0b","repo":"hashicorp/nomad","slug":"failed-to-send-input-w","errorCode":null,"errorMessage":"failed to send input: %w","messagePattern":"failed to send input: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/allocations_exec.go","lineNumber":71,"sourceCode":"\n\tsendErrCh := s.startTransmit(ctx, conn)\n\texitCh, recvErrCh := s.startReceiving(ctx, conn)\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn -2, ctx.Err()\n\t\tcase exitCode := <-exitCh:\n\t\t\treturn exitCode, nil\n\t\tcase recvErr := <-recvErrCh:\n\t\t\t// drop websocket code, not relevant to user\n\t\t\tif wsErr, ok := recvErr.(*websocket.CloseError); ok && wsErr.Text != \"\" {\n\t\t\t\treturn -2, errors.New(wsErr.Text)\n\t\t\t}\n\n\t\t\treturn -2, recvErr\n\t\tcase sendErr := <-sendErrCh:\n\t\t\treturn -2, fmt.Errorf(\"failed to send input: %w\", sendErr)\n\t\t}\n\t}\n}\n\nfunc (s *execSession) startConnection() (*websocket.Conn, error) {\n\t// First, attempt to connect to the node directly, but may fail due to network isolation\n\t// and network errors.  Fallback to using server-side forwarding instead.\n\tnodeClient, err := s.client.GetNodeClientWithTimeout(s.alloc.NodeID, ClientConnTimeout, s.q)\n\tif err == NodeDownErr {\n\t\treturn nil, NodeDownErr\n\t}\n\n\tq := s.q\n\tif q == nil {\n\t\tq = &QueryOptions{}\n\t}\n\tif q.Params == nil {\n\t\tq.Params = make(map[string]string)","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/api/allocations_exec.go#L53-L89","documentation":"In api/allocations_exec.go:71, the exec session's run loop watches a sendErrCh for failures writing to the exec websocket. When sending stdin/input to the running task fails, it terminates the exec session with exit code -2 and this wrapped error. It indicates the websocket connection used for streaming input to the allocation broke or was closed mid-session.","triggerScenarios":"Calling AllocSTW/Exec/ActionExec on an allocation and writing stdin while the websocket to the node is dead: node goes down mid-session, network interruption, node agent restarts, or the connection was closed server-side.","commonSituations":"Long-running interactive exec sessions where the target node drains or restarts; laptops sleeping mid-session killing the TCP connection; network isolation between client and node; NAT/firewall idle timeouts dropping the websocket.","solutions":["Inspect the wrapped %w error — a websocket close error reveals whether the node or network closed the connection","Re-establish the exec session (retry Exec) — sessions are not resumable","Check node health and allocation status; if the node drained, reschedule the allocation elsewhere","Keep the connection alive (application-level ping/keepalive) or shorten session duration behind proxies with idle timeouts","Verify network connectivity/firewall rules allow websocket traffic to the node's HTTPAddr"],"exampleFix":"// before\nexitCode, err := allocs.Exec(allocID, task, tty, commands, stdin, stdout, stderr, q)\nif err != nil { return err }\n// after: handle send failure as a retryable connection loss\nexitCode, err := allocs.Exec(allocID, task, tty, commands, stdin, stdout, stderr, q)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to send input\") {\n        return fmt.Errorf(\"exec connection lost, re-establishing session: %w\", err)\n    }\n    return err\n}","handlingStrategy":"retry","validationCode":"// pre-flight: confirm the allocation is running on a healthy node\nalloc, _, err := client.Allocations().Info(allocID, nil)\nif err != nil || alloc.ClientStatus == \"failed\" { return fmt.Errorf(\"allocation not viable for exec\") }","typeGuard":null,"tryCatchPattern":"exit, err := execSession()\nif err != nil && strings.Contains(err.Error(), \"failed to send input\") {\n\t// transient connection loss: recreate the session with backoff\n\treturn retryWithBackoff(3, execSession)\n}","preventionTips":["Avoid long-lived exec sessions across network changes (sleep/wake, VPN reconnect)","Keep idle keepalives enabled so NAT/firewall timeouts do not drop the websocket","Check node drains before starting interactive exec","Treat exit code -2 as connection-loss, not command failure"],"tags":["websocket","exec","network","nomad-api"],"backgroundTag":"websocket-connection-closed","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"}