{"record":{"id":"f85823dba252688a","repo":"grpc/grpc-go","slug":"the-stream-server-interceptor-was-already-set-and","errorCode":null,"errorMessage":"The stream server interceptor was already set and may not be reset.","messagePattern":"The stream server interceptor was already set and may not be reset\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"server.go","lineNumber":509,"sourceCode":"\t})\n}\n\n// ChainUnaryInterceptor returns a ServerOption that specifies the chained interceptor\n// for unary RPCs. The first interceptor will be the outer most,\n// while the last interceptor will be the inner most wrapper around the real call.\n// All unary interceptors added by this method will be chained.\nfunc ChainUnaryInterceptor(interceptors ...UnaryServerInterceptor) ServerOption {\n\treturn newFuncServerOption(func(o *serverOptions) {\n\t\to.chainUnaryInts = append(o.chainUnaryInts, interceptors...)\n\t})\n}\n\n// StreamInterceptor returns a ServerOption that sets the StreamServerInterceptor for the\n// server. Only one stream interceptor can be installed.\nfunc StreamInterceptor(i StreamServerInterceptor) ServerOption {\n\treturn newFuncServerOption(func(o *serverOptions) {\n\t\tif o.streamInt != nil {\n\t\t\tpanic(\"The stream server interceptor was already set and may not be reset.\")\n\t\t}\n\t\to.streamInt = i\n\t})\n}\n\n// ChainStreamInterceptor returns a ServerOption that specifies the chained interceptor\n// for streaming RPCs. The first interceptor will be the outer most,\n// while the last interceptor will be the inner most wrapper around the real call.\n// All stream interceptors added by this method will be chained.\nfunc ChainStreamInterceptor(interceptors ...StreamServerInterceptor) ServerOption {\n\treturn newFuncServerOption(func(o *serverOptions) {\n\t\to.chainStreamInts = append(o.chainStreamInts, interceptors...)\n\t})\n}\n\n// InTapHandle returns a ServerOption that sets the tap handle for all the server\n// transport to be created. Only one can be installed.\n//","sourceCodeStart":491,"sourceCodeEnd":527,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/server.go#L491-L527","documentation":"grpc.StreamInterceptor (server.go:506) installs a single non-chained streaming server interceptor and panics if one is already set (o.streamInt != nil), for the same anti-silent-overwrite reason as UnaryInterceptor. The panic occurs at NewServer construction time when the option function runs.","triggerScenarios":"Passing grpc.StreamInterceptor(...) more than once in NewServer's options, or merging option slices that each contain a StreamInterceptor.","commonSituations":"A base option set (from a shared server builder) already registers a stream interceptor and the caller adds another; refactoring interceptors without removing the old single-interceptor registration.","solutions":["Use grpc.ChainStreamInterceptor(a, b, ...) once instead of multiple StreamInterceptor calls.","Deduplicate StreamInterceptor entries across all merged option slices.","Have framework code expose a chaining slot rather than calling StreamInterceptor itself."],"exampleFix":"// before\nsrv := grpc.NewServer(\n    grpc.StreamInterceptor(recoveryStreamInt),\n    grpc.StreamInterceptor(metricsStreamInt), // panics: already set\n)\n\n// after\nsrv := grpc.NewServer(\n    grpc.ChainStreamInterceptor(recoveryStreamInt, metricsStreamInt),\n)","handlingStrategy":"validation","validationCode":"// Standardize stream interceptor assembly through chaining\nstreamInts := []grpc.StreamServerInterceptor{recoveryInt, metricsInt}\nopts := []grpc.ServerOption{grpc.ChainStreamInterceptor(streamInts...)}\nsrv := grpc.NewServer(opts...)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use ChainStreamInterceptor exclusively; reserve StreamInterceptor for single-interceptor servers.","Centralize server-option construction so two StreamInterceptor entries cannot collide.","Review framework code that may register a stream interceptor on your behalf."],"tags":["server","interceptor","streaming","panic","grpc-go","config"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}