micro/go-micro · warning

streamer not implemented

Error message

streamer not implemented

What it means

rpcStream.CloseSend in client/rpc_stream.go:148 unconditionally returns errors.New("streamer not implemented"). The generic RPC stream abstraction does not support half-closing the send side of a stream, so any attempt to signal "no more messages from me" via this API fails. It is a deliberate stub, not a runtime condition.

Source

Thrown at client/rpc_stream.go:148

		if err != nil {
			r.err = err
		}
	}

	defer r.Unlock()

	return r.err
}

func (r *rpcStream) Error() error {
	r.RLock()
	defer r.RUnlock()

	return r.err
}

func (r *rpcStream) CloseSend() error {
	return errors.New("streamer not implemented")
}

func (r *rpcStream) Close() error {
	r.Lock()

	select {
	case <-r.closed:
		r.Unlock()
		return nil
	default:
		close(r.closed)
		r.Unlock()

		// send the end of stream message
		if r.sendEOS {
			// no need to check for error
			//nolint:errcheck,gosec
			r.codec.Write(&codec.Message{

View on GitHub (pinned to 24529f1404)

Solutions

  1. Remove the CloseSend call — with the micro client you signal end-of-request by sending the request once, not by half-closing
  2. Rely on stream.Close() when done, accepting that it also closes the read side
  3. If half-close semantics are required, use the native gRPC client instead of the micro rpcStream abstraction

Example fix

// before
stream.Send(req)
if err := stream.CloseSend(); err != nil { return err }
for stream.Recv(rsp) { ... }
// after
stream.Send(req)
for stream.Recv(rsp) { ... }
stream.Close()
Defensive patterns

Strategy: validation

Validate before calling

// never call CloseSend on a micro rpcStream; if you need half-close,
// verify the concrete stream type first:
if cs, ok := stream.(interface{ CloseSend() error }); ok && !isRpcStream(stream) {
    _ = cs.CloseSend()
}

Type guard

func supportsCloseSend(s interface{}) bool {
    _, ok := s.(interface{ CloseSend() error })
    return ok && !isRpcStream(s)
}

Try / catch

if err := stream.CloseSend(); err != nil && strings.Contains(err.Error(), "streamer not implemented") {
    // expected on micro rpcStream; ignore and rely on Send/Recv semantics
    err = nil
}

Prevention

When it happens

Trigger: Any call to (*rpcStream).CloseSend — there is no code path where it succeeds. Typically invoked by code ported from gRPC-native clients where CloseSend is valid.

Common situations: Porting grpc.ClientStream code (which uses CloseSend before draining responses) onto the micro client; protocol implementations that require half-close semantics; generic streaming middleware calling CloseSend defensively.

Related errors


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