{"record":{"id":"850e3febb04ab9f2","repo":"micro/go-micro","slug":"subscriber-error-s","errorCode":null,"errorMessage":"subscriber error: %s","messagePattern":"subscriber error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/grpc/subscriber.go","lineNumber":270,"sourceCode":"\t\t\t\t}\n\t\t\t\terr := fn(ctx, &rpcMessage{\n\t\t\t\t\ttopic:       sb.topic,\n\t\t\t\t\tcontentType: ct,\n\t\t\t\t\tpayload:     req.Interface(),\n\t\t\t\t\theader:      msg.Header,\n\t\t\t\t\tbody:        msg.Body,\n\t\t\t\t})\n\t\t\t\tresults <- err\n\t\t\t}()\n\t\t}\n\t\tvar errors []string\n\t\tfor i := 0; i < len(sb.handlers); i++ {\n\t\t\tif rerr := <-results; rerr != nil {\n\t\t\t\terrors = append(errors, rerr.Error())\n\t\t\t}\n\t\t}\n\t\tif len(errors) > 0 {\n\t\t\terr = fmt.Errorf(\"subscriber error: %s\", strings.Join(errors, \"\\n\"))\n\t\t}\n\n\t\treturn err\n\t}\n}\n\nfunc (s *subscriber) Topic() string {\n\treturn s.topic\n}\n\nfunc (s *subscriber) Subscriber() interface{} {\n\treturn s.subscriber\n}\n\nfunc (s *subscriber) Endpoints() []*registry.Endpoint {\n\treturn s.endpoints\n}\n","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/server/grpc/subscriber.go#L252-L288","documentation":"When a message is delivered, the gRPC subscriber runs each registered handler in parallel and collects handler errors. If one or more handlers returned errors, Subscribe's message-handling function aggregates them into a single error formatted as `subscriber error: <joined messages>`. It tells you the message was received but at least one subscriber handler failed.","triggerScenarios":"Publishing to a topic where one or more registered subscriber handler methods return a non-nil error; the error strings of all failing handlers are joined with newlines.","commonSituations":"A handler's business logic fails (DB down, validation error); a decode error in a handler; one bad subscriber causing publishers to see errors even though other handlers succeeded.","solutions":["Read the joined error strings to identify which handler(s) failed and fix the root cause in those handlers","Add error handling/logging inside each subscriber handler so expected failures do not propagate as errors","If handlers legitimately disagree about success, isolate them (separate topics/subscribers) so one failure does not fail the whole delivery"],"exampleFix":"// before\nfunc (h *handler) Handle(ctx context.Context, e *Event) error { return process(e) }\n// after\nfunc (h *handler) Handle(ctx context.Context, e *Event) error {\n    if err := process(e); err != nil {\n        log.Errorf(\"handle event: %v\", err)\n        return nil // or return err if delivery should fail\n    }\n    return nil\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := server.Publish(ctx, msg); err != nil {\n\tvar subErr error\n\tif strings.HasPrefix(err.Error(), \"subscriber error: \") {\n\t\tdetail := strings.TrimPrefix(err.Error(), \"subscriber error: \")\n\t\tfor _, line := range strings.Split(detail, \"\\n\") {\n\t\t\tlog.Errorf(\"subscriber failed: %s\", line)\n\t\t}\n\t} else {\n\t\t// transport-level failure: safe to retry\n\t\terr = retry(err)\n\t}\n\t_ = subErr\n}","preventionTips":["Make handlers defensive: recover panics and log non-fatal errors instead of returning them","Subscribe a dead-letter handler to capture and inspect failed deliveries","Monitor the 'subscriber error:' prefix in publisher logs as a signal that a consumer is unhealthy"],"tags":["grpc","subscriber","handler-error","go"],"backgroundTag":"subscriber-handler-failed","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}