{"record":{"id":"70858839a86e5937","repo":"hashicorp/consul","slug":"client-streams-are-unsupported","errorCode":null,"errorMessage":"client streams are unsupported","messagePattern":"client streams are unsupported","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/tools/protoc-gen-grpc-clone/internal/generate/generate.go","lineNumber":83,"sourceCode":"\tfilename := file.GeneratedFilenamePrefix + \"_cloning_grpc.pb.go\"\n\tgenFile := g.p.NewGeneratedFile(filename, file.GoImportPath)\n\n\tfor _, svc := range file.Services {\n\t\tsvcTypes := &cloningServiceTypes{\n\t\t\tClientTypeName:        genFile.QualifiedGoIdent(protogen.GoIdent{GoName: svc.GoName + \"Client\", GoImportPath: file.GoImportPath}),\n\t\t\tServerTypeName:        genFile.QualifiedGoIdent(protogen.GoIdent{GoName: svc.GoName + \"Server\", GoImportPath: file.GoImportPath}),\n\t\t\tCloningClientTypeName: genFile.QualifiedGoIdent(protogen.GoIdent{GoName: \"Cloning\" + svc.GoName + \"Client\", GoImportPath: file.GoImportPath}),\n\t\t\tServiceName:           svc.GoName,\n\t\t}\n\n\t\ttsvc := cloningService{\n\t\t\tcloningServiceTypes: svcTypes,\n\t\t}\n\n\t\tfor _, method := range svc.Methods {\n\t\t\tif method.Desc.IsStreamingClient() {\n\t\t\t\t// when we need these we can implement this\n\t\t\t\tpanic(\"client streams are unsupported\")\n\t\t\t}\n\n\t\t\tif method.Desc.IsStreamingServer() {\n\t\t\t\ttsvc.ServerStreamMethods = append(tsvc.ServerStreamMethods, &inmemMethod{\n\t\t\t\t\tcloningServiceTypes: svcTypes,\n\t\t\t\t\tMethod:              method,\n\t\t\t\t})\n\n\t\t\t\t// record that we need to also generate the inmem stream client code\n\t\t\t\t// into this directory\n\t\t\t\tg.directories[filepath.Dir(filename)] = pkgInfo{impPath: file.GoImportPath, pkgName: file.GoPackageName}\n\t\t\t} else {\n\t\t\t\ttsvc.UnaryMethods = append(tsvc.UnaryMethods, &inmemMethod{\n\t\t\t\t\tcloningServiceTypes: svcTypes,\n\t\t\t\t\tMethod:              method,\n\t\t\t\t})\n\t\t\t}\n\t\t}","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/hashicorp/consul/blob/2397ff0d763d34f2fe37fe59fde6a7f7fc430a3e/internal/tools/protoc-gen-grpc-clone/internal/generate/generate.go#L65-L101","documentation":"The protoc-gen-grpc-clone plugin panics during code generation (internal/tools/protoc-gen-grpc-clone/internal/generate/generate.go:83) when a service method declares a client stream (streaming request). The generator only implements cloning code for unary and server-streaming methods; the comment 'when we need these we can implement this' marks client streams as unimplemented. This is a build-time/codegen crash, not a runtime error: protoc exits non-zero and no Go output is produced for that run.","triggerScenarios":"Running proto generation (make proto / protoc with --go-grpc-clone or equivalent plugin invocation) on a .proto containing 'rpc Foo (stream Req) returns (Resp)' or a bidi 'rpc Chat (stream A) returns (stream B)'.","commonSituations":"Adding a client-streaming or bidi-streaming RPC to a proto covered by the grpc-clone generator in the Consul repo; copying an external proto with streaming methods into the generation path; upgrading protoc toolchains without checking method shapes.","solutions":["Redesign the RPC to be unary or server-streaming (server streams ARE supported and generate inmem stream client code)","Move the streaming service into a separate .proto file that is excluded from grpc-clone generation","If the stream is genuinely required, implement client-stream support in the generator (extend inmemMethod for request streams)","Add a pre-generation lint that greps protos for 'stream' in the request position so CI fails with a clear message instead of a protoc panic"],"exampleFix":"// before (proto)\nservice Metrics {\n  rpc Export (stream Payload) returns (Ack); // client stream -> plugin panics\n}\n\n// after (proto)\nservice Metrics {\n  rpc Export (Payload) returns (Ack);          // unary: supported\n  rpc Watch (Req) returns (stream Resp);        // server stream: supported\n}","handlingStrategy":"validation","validationCode":"#!/bin/sh\n# fail before protoc runs if any request position uses 'stream'\nif grep -rnE 'rpc +[A-Za-z0-9_]+ *\\( *stream' proto/ ; then\n\techo \"client-streaming RPCs are unsupported by protoc-gen-grpc-clone\" >&2\n\texit 1\nfi\nprotoc --plugin=protoc-gen-grpc-clone ...","typeGuard":null,"tryCatchPattern":"// in the plugin's main, turn the panic into a clean codegen failure\ndefer func() {\n\tif r := recover(); r != nil {\n\t\tfmt.Fprintf(os.Stderr, \"protoc-gen-grpc-clone: %v\\n\", r)\n\t\tos.Exit(1)\n\t}\n}()","preventionTips":["Keep streaming methods out of protos processed by grpc-clone, or gate them behind a lint in CI","Remember server streams are supported; only the request (client) side panics","When copying protos from other projects, audit method shapes before wiring them into generation"],"tags":["go","protobuf","protoc","codegen","grpc","streaming","panic","consul"],"backgroundTag":null,"analyzedSha":"2397ff0d763d34f2fe37fe59fde6a7f7fc430a3e","analyzedAt":"2026-08-15T19:19:47.700Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}