{"record":{"id":"ffa4481f6245b0d8","repo":"wavetermdev/waveterm","slug":"response-packets-may-not-have-timeout-set","errorCode":null,"errorMessage":"response packets may not have timeout set","messagePattern":"response packets may not have timeout set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshutil/wshrpc.go","lineNumber":190,"sourceCode":"\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}\n\nfunc validateServerImpl(serverImpl ServerImpl) {\n\tif serverImpl == nil {\n\t\treturn\n\t}\n\tserverType := reflect.TypeOf(serverImpl)","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshutil/wshrpc.go#L172-L208","documentation":"Packet validation error: RESPONSE packets must not carry a timeout. Timeouts are specified by the requester on the command; echoing a timeout on a response is a protocol violation and the packet is rejected.","triggerScenarios":"Building or copying an RpcMessage where Timeout (or the opts timeout carried into the message) survives from a request into a response packet with ResId set.","commonSituations":"Cloning a request message and mutating it into a response without clearing Timeout; middleware that forwards all fields of an incoming packet back out; serialization of stale cached messages.","solutions":["Zero out Timeout on any packet carrying ResId before validating/sending.","Build responses from scratch (only ResId, ReqId, data) instead of mutating request messages.","Use the handler-based response APIs (SendResponse/SendComplexRequest) so field ownership is explicit."],"exampleFix":"// before\nresp := reqMsg // carries Timeout\nresp.ResId = \"res-1\"\n// after\nresp := wshrpc.RpcMessage{ResId: \"res-1\", ReqId: reqMsg.ReqId}","handlingStrategy":"validation","validationCode":"func checkResNoTimeout(m wshrpc.RpcMessage) error {\n    if m.ResId != \"\" && m.Timeout != 0 {\n        return fmt.Errorf(\"response packet has timeout set\")\n    }\n    return nil\n}","typeGuard":"func isCleanResponse(m wshrpc.RpcMessage) bool {\n    return m.ResId != \"\" && m.Command == \"\" && m.Timeout == 0 && m.ReqId != \"\"\n}","tryCatchPattern":null,"preventionTips":["Build response packets from scratch rather than mutating request packets.","Keep Timeout only in request options (RpcOpts), never in response messages.","Sanitize packets in any forwarding/middleware layer before re-emitting them."],"tags":["rpc","protocol-validation","timeout"],"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"}