{"record":{"id":"2de237fca057e9fc","repo":"hashicorp/nomad","slug":"failed-to-marshal-command-w","errorCode":null,"errorMessage":"failed to marshal command: %W","messagePattern":"failed to marshal command: %W","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/allocations_exec.go","lineNumber":94,"sourceCode":"func (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)\n\t}\n\n\tcommandBytes, err := json.Marshal(s.command)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to marshal command: %W\", err)\n\t}\n\n\tq.Params[\"tty\"] = strconv.FormatBool(s.tty)\n\tq.Params[\"task\"] = s.task\n\tq.Params[\"command\"] = string(commandBytes)\n\treqPath := fmt.Sprintf(\"/v1/client/allocation/%s/exec\", s.alloc.ID)\n\n\tif s.action != \"\" {\n\t\tq.Params[\"action\"] = s.action\n\t\tq.Params[\"allocID\"] = s.alloc.ID\n\t\tq.Params[\"group\"] = s.alloc.TaskGroup\n\t\treqPath = fmt.Sprintf(\"/v1/job/%s/action\", url.PathEscape(s.job))\n\t}\n\n\tvar conn *websocket.Conn\n\n\tif nodeClient != nil {\n\t\tconn, _, _ = nodeClient.websocket(reqPath, q) //nolint:bodyclose // gorilla/websocket Dialer.DialContext() does not require the body to be closed.","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/api/allocations_exec.go#L76-L112","documentation":"In api/allocations_exec.go:94, startConnection json.Marshal's the exec command struct before embedding it as a query parameter. Marshal of a plain struct with strings/bools essentially never fails, so this error is practically unreachable; if it fires, the ExecStreamingInput/command structure contains a value json cannot encode. Note the format verb is a (invalid) capitalized %W — it still behaves like %v, so the wrapped error is not unwrappable via errors.Is/As.","triggerScenarios":"Calling Exec/ActionExec where s.command fails to JSON-marshal — only possible if the command struct is modified to include unsupported types (channels, funcs, cyclic data). Not triggerable with the standard library's command types.","commonSituations":"Forking/patching the Nomad API package and adding a field with an unsupported type to the exec command struct; building the command with a custom type lacking MarshalJSON.","solutions":["Inspect the wrapped error to identify which field fails to marshal","Ensure all fields of the exec command struct are JSON-encodable (strings, bools, slices)","If you patched the package, revert the unsupported field or add a MarshalJSON method","Report upstream if this occurs with an unmodified client — it indicates a version incompatibility"],"exampleFix":"// before (in a patched struct)\nCommand struct{ Args []string; Notify chan int `json:\"notify\"` }\n// after: remove or encode the unmarshalable field\nCommand struct{ Args []string }","handlingStrategy":"validation","validationCode":"if _, err := json.Marshal(cmd); err != nil {\n\treturn fmt.Errorf(\"command not encodable: %w\", err)\n}","typeGuard":"func jsonEncodable(v any) bool {\n\tb, err := json.Marshal(v)\n\treturn err == nil && b != nil\n}","tryCatchPattern":"conn, err := s.startConnection()\nif err != nil && strings.Contains(err.Error(), \"failed to marshal command\") {\n\treturn fmt.Errorf(\"client bug: exec command struct not JSON-encodable: %w\", err)\n}","preventionTips":["Keep exec command structs limited to JSON-native types","Add marshal smoke tests if you vendor/patch the api package","Prefer strings/bools/slices over custom types in command payloads"],"tags":["json","exec","nomad-api"],"backgroundTag":"json-marshal-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"}