micro/go-micro · error

subscriber error: %s

Error message

subscriber error: %s

What it means

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.

Source

Thrown at server/grpc/subscriber.go:270

				}
				err := fn(ctx, &rpcMessage{
					topic:       sb.topic,
					contentType: ct,
					payload:     req.Interface(),
					header:      msg.Header,
					body:        msg.Body,
				})
				results <- err
			}()
		}
		var errors []string
		for i := 0; i < len(sb.handlers); i++ {
			if rerr := <-results; rerr != nil {
				errors = append(errors, rerr.Error())
			}
		}
		if len(errors) > 0 {
			err = fmt.Errorf("subscriber error: %s", strings.Join(errors, "\n"))
		}

		return err
	}
}

func (s *subscriber) Topic() string {
	return s.topic
}

func (s *subscriber) Subscriber() interface{} {
	return s.subscriber
}

func (s *subscriber) Endpoints() []*registry.Endpoint {
	return s.endpoints
}

View on GitHub (pinned to 24529f1404)

Solutions

  1. Read the joined error strings to identify which handler(s) failed and fix the root cause in those handlers
  2. Add error handling/logging inside each subscriber handler so expected failures do not propagate as errors
  3. If handlers legitimately disagree about success, isolate them (separate topics/subscribers) so one failure does not fail the whole delivery

Example fix

// before
func (h *handler) Handle(ctx context.Context, e *Event) error { return process(e) }
// after
func (h *handler) Handle(ctx context.Context, e *Event) error {
    if err := process(e); err != nil {
        log.Errorf("handle event: %v", err)
        return nil // or return err if delivery should fail
    }
    return nil
}
Defensive patterns

Strategy: try-catch

Try / catch

if err := server.Publish(ctx, msg); err != nil {
	var subErr error
	if strings.HasPrefix(err.Error(), "subscriber error: ") {
		detail := strings.TrimPrefix(err.Error(), "subscriber error: ")
		for _, line := range strings.Split(detail, "\n") {
			log.Errorf("subscriber failed: %s", line)
		}
	} else {
		// transport-level failure: safe to retry
		err = retry(err)
	}
	_ = subErr
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/850e3febb04ab9f2. Report an issue: GitHub.