{"record":{"id":"5164a55ec821294e","repo":"hashicorp/nomad","slug":"error-marshaling-json-for-stream-w","errorCode":null,"errorMessage":"error marshaling json for stream: %w","messagePattern":"error marshaling json for stream: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/stream/ndjson.go","lineNumber":85,"sourceCode":"\t\t\tcase <-n.ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Send encodes an object into Newline delimited json. An error is returned\n// if json encoding fails or if the stream is no longer running.\nfunc (n *JsonStream) Send(v any) error {\n\tif n.ctx.Err() != nil {\n\t\treturn n.ctx.Err()\n\t}\n\n\tvar buf bytes.Buffer\n\tenc := codec.NewEncoder(&buf, structs.JsonHandleWithExtensions)\n\terr := enc.Encode(v)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error marshaling json for stream: %w\", err)\n\t}\n\n\tselect {\n\tcase <-n.ctx.Done():\n\t\treturn fmt.Errorf(\"error stream is no longer running: %w\", err)\n\tcase n.outCh <- &structs.EventJson{Data: buf.Bytes()}:\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":67,"sourceCodeEnd":96,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/stream/ndjson.go#L67-L96","documentation":"The NDJSON stream writer (used for exec streaming and event streams) encodes each outgoing value with a codec (JSON with extensions) before pushing to outCh. If enc.Encode fails — the value is not JSON-encodable (unsupported types, unserializable extensions, invalid map keys) — Send returns this wrapped error and the stream aborts.","triggerScenarios":"Calling n.Send(v) (jsonStream, exec streaming handlers like execStreaming/ExecTaskStreamingRaw) with a value that codec/Encode cannot marshal to JSON with extensions.","commonSituations":"Sending raw messages containing non-UTF-8 bytes or invalid types in an exec stdin/stdout frame; custom structs with channels/funcs or cyclic references accidentally passed to the stream; msgpack-style extension data that violates the JSON handle rules.","solutions":["Log the wrapped cause and inspect the value being sent for non-encodable fields (func, chan, cycles, invalid map keys).","Sanitize/normalize the payload before Send (convert binary data to base64 strings; only send documented structs like structs.StreamFrame / EventJson).","Add a test asserting the exact payload type marshals with structs.JsonHandleWithExtensions.","If caused by a Nomad version's exec protocol mismatch, upgrade client and server together."],"exampleFix":"// before\nerr := stream.Send(rawMsg) // rawMsg contains []byte fields\n// after\nsafe := struct {\n  Data string `json:\"data\"`\n}{Data: base64.StdEncoding.EncodeToString(rawMsg.Data)}\nif err := stream.Send(safe); err != nil { return err }","handlingStrategy":"validation","validationCode":"// Ensure the payload is JSON-encodable with the same codec before Send\nfunc assertEncodable(v interface{}) error {\n  var buf bytes.Buffer\n  return codec.NewEncoder(&buf, structs.JsonHandleWithExtensions).Encode(v)\n}","typeGuard":"func isStreamMarshalError(err error) bool { return err != nil && strings.Contains(err.Error(), \"error marshaling json for stream\") }","tryCatchPattern":"if err := n.Send(v); err != nil {\n  if isStreamMarshalError(err) {\n    logger.Error(\"unencodable stream payload\", \"type\", fmt.Sprintf(\"%T\", v), \"err\", err)\n    return err // stream aborted; do not retry same payload\n  }\n  return err\n}","preventionTips":["Only send documented stream structs (StreamFrame, EventJson) over NDJSON streams.","Encode binary data as base64; avoid func/chan/cyclic fields in payloads.","Add unit tests that marshal payloads with structs.JsonHandleWithExtensions."],"tags":["nomad","streaming","json","serialization"],"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"}