{"record":{"id":"c98fc990851daa33","repo":"wavetermdev/waveterm","slug":"response-packets-may-not-have-command-set","errorCode":null,"errorMessage":"response packets may not have command set","messagePattern":"response packets may not have command set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshutil/wshrpc.go","lineNumber":184,"sourceCode":"\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}\n\treturn fmt.Errorf(\"invalid packet: must have command, reqid, or resid set\")\n}\n\ntype rpcData struct {\n\tCommand string\n\tRoute   string\n\tResCh   chan *RpcMessage\n\tHandler *RpcRequestHandler\n}","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshutil/wshrpc.go#L166-L202","documentation":"Validate() in pkg/wshutil/wshrpc.go checks that each RpcMessage conforms to the packet protocol. A response packet is identified by having ResId set; responses are only acknowledgments/data for a prior request, so they must never carry a Command. This error means a packet marked as a response was built with a command field filled in.","triggerScenarios":"Manually constructing or marshaling an RpcMessage with both ResId and Command set, or replying via a response path while accidentally copying the original request's Command field into the reply.","commonSituations":"Custom RPC client code that echoes request fields into responses; version drift where one side serializes packets with command carried over; hand-written test fixtures for WSH RPC messages.","solutions":["Remove the Command field from the response packet; keep only ResId, ReqId, and the response data.","If you intended to send a new command, clear ResId instead and set Command/ReqId as a request packet.","Use SendResponse/SendResponseError on RpcResponseHandler rather than hand-building response RpcMessages.","Run Validate() on locally built packets in tests to catch malformed shapes early."],"exampleFix":"// before\nmsg := wshrpc.RpcMessage{Command: \"waveclient:get\", ResId: \"res-1\", ReqId: \"req-1\"}\n// after\nmsg := wshrpc.RpcMessage{ResId: \"res-1\", ReqId: \"req-1\"}","handlingStrategy":"validation","validationCode":"func validRes(m wshrpc.RpcMessage) error {\n    if m.ResId != \"\" && m.Command != \"\" {\n        return fmt.Errorf(\"response packet has command set: %v\", m.Command)\n    }\n    return nil\n}","typeGuard":"func isPureResponse(m wshrpc.RpcMessage) bool {\n    return m.ResId != \"\" && m.Command == \"\"\n}","tryCatchPattern":null,"preventionTips":["Never reuse request structs/messages to build responses — construct fresh RpcMessage values.","Route all responses through RpcResponseHandler.SendResponse instead of manual packet assembly.","Run Validate() in unit tests on every packet shape your code emits.","Clear Command/Timeout fields when transforming requests into responses."],"tags":["rpc","protocol-validation","packet-validation"],"backgroundTag":"rpc-packet-validation-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}