{"record":{"id":"c017de44fe9784a9","repo":"wavetermdev/waveterm","slug":"response-packets-must-have-reqid-set","errorCode":null,"errorMessage":"response packets must have reqid set","messagePattern":"response packets must have reqid set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshutil/wshrpc.go","lineNumber":187,"sourceCode":"\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}\n\nfunc validateServerImpl(serverImpl ServerImpl) {\n\tif serverImpl == nil {","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshutil/wshrpc.go#L169-L205","documentation":"A response packet (ResId set) must carry the ReqId of the original request so the caller's pending request can be correlated and resolved. Validate() rejects responses lacking ReqId because they cannot be routed back to any awaiting request.","triggerScenarios":"Constructing an RpcMessage with ResId but leaving ReqId empty — e.g., building a reply manually without reading the request's ReqId, or a response path that drops the correlation id.","commonSituations":"Hand-rolled response messages in tooling or tests; losing the request id when forwarding packets between connections; correlating responses across restarted connections.","solutions":["Set ReqId to the request id from the incoming request before sending the response.","Reply via RpcResponseHandler.SendResponse, which fills ReqId automatically from the handler.","If the packet is not a response, remove ResId; a pure command packet needs Command/ReqId instead.","Log and inspect the raw packet (EnableRpcDebug) to confirm which fields are actually populated."],"exampleFix":"// before\nmsg := wshrpc.RpcMessage{ResId: \"res-1\"}\n// after\nmsg := wshrpc.RpcMessage{ResId: \"res-1\", ReqId: origReqId}","handlingStrategy":"validation","validationCode":"func checkResReqId(m wshrpc.RpcMessage) error {\n    if m.ResId != \"\" && m.ReqId == \"\" {\n        return fmt.Errorf(\"response missing reqid\")\n    }\n    return nil\n}","typeGuard":"func isRoutableResponse(m wshrpc.RpcMessage) bool {\n    return m.ResId != \"\" && m.ReqId != \"\"\n}","tryCatchPattern":null,"preventionTips":["Always copy the incoming request's ReqId into your response.","Prefer handler-based response APIs that manage correlation ids for you.","Test response correlation with a live round-trip RPC in CI.","Validate packets before writing to OutputCh."],"tags":["rpc","protocol-validation","request-correlation"],"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"}