{"record":{"id":"0a3ae3fcfd823586","repo":"grafana/k6","slug":"invalid-grpc-stream-s-parameters-w","errorCode":null,"errorMessage":"invalid GRPC Stream's parameters: %w","messagePattern":"invalid GRPC Stream's parameters: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/grpc/grpc.go","lineNumber":128,"sourceCode":"\n// stream returns a new stream object\nfunc (mi *ModuleInstance) stream(c sobek.ConstructorCall) *sobek.Object {\n\trt := mi.vu.Runtime()\n\n\tclient, err := extractClient(c.Argument(0), rt)\n\tif err != nil {\n\t\tcommon.Throw(rt, fmt.Errorf(\"invalid GRPC Stream's client: %w\", err))\n\t}\n\n\tmethodName := sanitizeMethodName(c.Argument(1).String())\n\tmethodDescriptor, err := client.getMethodDescriptor(methodName)\n\tif err != nil {\n\t\tcommon.Throw(rt, fmt.Errorf(\"invalid GRPC Stream's method: %w\", err))\n\t}\n\n\tp, err := newCallParams(mi.vu, c.Argument(2))\n\tif err != nil {\n\t\tcommon.Throw(rt, fmt.Errorf(\"invalid GRPC Stream's parameters: %w\", err))\n\t}\n\n\tp.SetSystemTags(mi.vu.State(), client.addr, methodName)\n\n\tlogger := mi.vu.State().Logger.WithField(\"streamMethod\", methodName)\n\n\ts := &stream{\n\t\tvu:               mi.vu,\n\t\tclient:           client,\n\t\tmethodDescriptor: methodDescriptor,\n\t\tmethod:           methodName,\n\t\tlogger:           logger,\n\n\t\ttq: taskqueue.New(mi.vu.RegisterCallback),\n\n\t\tinstanceMetrics: mi.metrics,\n\t\tbuiltinMetrics:  mi.vu.State().BuiltinMetrics,\n\t\tdone:            make(chan struct{}),","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/grpc/grpc.go#L110-L146","documentation":"The optional third argument of new grpc.Stream(client, method, params) is validated by newCallParams(), which accepts only four keys: metadata, tags, timeout and discardResponseMessage. Any failure inside that validation (bad metadata object, non-scalar tag value, unparseable timeout, unknown key) is wrapped and rethrown as \"invalid GRPC Stream's parameters\".","triggerScenarios":"new grpc.Stream(client, method, { headers: {...} }) (unknown key); { metadata: { 'x-bin': 'text' } } (binary key with a string value); { timeout: 'soon' }; { tags: { user: {} } }.","commonSituations":"Reusing a params object built for client.invoke() that carries extra keys; sharing an HTTP-flavoured options helper across protocols; key names drifting between k6 versions.","solutions":["Read the wrapped cause after the colon in the message; it names the exact offending key and expected type","Keep only metadata, tags, timeout and discardResponseMessage in the object","Validate the params object with a helper before passing it (see defense)"],"exampleFix":"// before\nconst stream = new grpc.Stream(client, METHOD, { headers: { 'x-tag': 'v' } });\n\n// after\nconst stream = new grpc.Stream(client, METHOD, { metadata: { 'x-tag': 'v' } });","handlingStrategy":"validation","validationCode":"const CALL_PARAM_KEYS = new Set(['metadata', 'tags', 'timeout', 'discardResponseMessage']);\nfunction assertCallParams(p) {\n  if (p == null) return;\n  for (const k of Object.keys(p)) {\n    if (!CALL_PARAM_KEYS.has(k)) throw new Error(`unknown grpc param '${k}'`);\n  }\n  if (p.timeout != null && !isDurationValue(p.timeout)) throw new Error('invalid timeout');\n  if (p.metadata != null) assertGrpcMetadata(p.metadata);\n}\nassertCallParams(params);\nconst stream = new grpc.Stream(client, METHOD, params);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build grpc params objects from scratch instead of reusing HTTP options objects","Centralize params construction in one helper so validation runs in one place","Log the wrapped cause whenever a params error is caught"],"tags":["grpc","stream","params","validation"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}