{"record":{"id":"e0311be075f77a59","repo":"wavetermdev/waveterm","slug":"request-packets-must-have-resid-set","errorCode":null,"errorMessage":"request packets must have resid set","messagePattern":"request packets must have resid set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshutil/wshrpc.go","lineNumber":175,"sourceCode":"\t\t\treturn fmt.Errorf(\"cancel packets may not have data set\")\n\t\t}\n\t\treturn nil\n\t}\n\tif r.Command != \"\" {\n\t\tif r.ResId != \"\" {\n\t\t\treturn fmt.Errorf(\"command packets may not have resid set\")\n\t\t}\n\t\tif r.Error != \"\" {\n\t\t\treturn fmt.Errorf(\"command packets may not have error set\")\n\t\t}\n\t\tif r.DataType != \"\" {\n\t\t\treturn fmt.Errorf(\"command packets may not have datatype set\")\n\t\t}\n\t\treturn nil\n\t}\n\tif r.ReqId != \"\" {\n\t\tif r.ResId == \"\" {\n\t\t\treturn fmt.Errorf(\"request packets must have resid set\")\n\t\t}\n\t\tif r.Timeout != 0 {\n\t\t\treturn fmt.Errorf(\"non-command request packets may not have timeout set\")\n\t\t}\n\t\treturn nil\n\t}\n\tif r.ResId != \"\" {\n\t\tif r.Command != \"\" {\n\t\t\treturn fmt.Errorf(\"response packets may not have command set\")\n\t\t}\n\t\tif r.ReqId == \"\" {\n\t\t\treturn fmt.Errorf(\"response packets must have reqid set\")\n\t\t}\n\t\tif r.Timeout != 0 {\n\t\t\treturn fmt.Errorf(\"response packets may not have timeout set\")\n\t\t}\n\t\treturn nil\n\t}","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshutil/wshrpc.go#L157-L193","documentation":"A packet with only ReqId set (no Command) is a follow-up/streaming request in an existing call. It must include ResId to identify which route/response stream it belongs to; otherwise the receiver cannot correlate it. Validate enforces ReqId implies ResId.","triggerScenarios":"Calling Validate on an RpcMessage with ReqId set, Command empty, and ResId empty.","commonSituations":"Streaming/stream-adjacent RPCs (e.g. terminal output, event chunks) where continuation packets forget the ResId; hand-rolled client code sending raw ReqId packets.","solutions":["Set ResId on the follow-up packet to match the ongoing response stream","Ensure the sender uses the library's response helpers rather than manual message construction","Add a Validate() call before sending to catch this at the producer"],"exampleFix":"// before\nmsg := wshutil.RpcMessage{ReqId: reqId, Data: chunk}\n// after\nmsg := wshutil.RpcMessage{ReqId: reqId, ResId: resId, Data: chunk}","handlingStrategy":"validation","validationCode":"if msg.ReqId != \"\" && msg.Command == \"\" && msg.ResId == \"\" {\n\treturn fmt.Errorf(\"follow-up request requires resid\")\n}\nif err := msg.Validate(); err != nil { return err }","typeGuard":"func isAddressedRequest(msg wshutil.RpcMessage) bool {\n\treturn msg.ReqId == \"\" || msg.ResId != \"\" || msg.Command != \"\"\n}","tryCatchPattern":"if err := msg.Validate(); err != nil {\n\treturn fmt.Errorf(\"request missing resid: %w\", err)\n}","preventionTips":["Always propagate ResId into streaming/follow-up packets","Prefer the library's response-writer helpers over manual packet building","Check stream continuation code paths after protocol upgrades"],"tags":["wsh","rpc","validation","streaming"],"backgroundTag":"invalid-rpc-packet","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}