micro/go-micro · info

connection header set to close

Error message

connection header set to close

What it means

In client/rpc_stream.go:180, rpcStream.Close closes the codec and then checks r.Error(); if the stream was marked with r.close and no other error occurred, it synthesizes errors.New("connection header set to close") as the stream error before releasing the connection. This signals that the connection was intentionally torn down because the close flag was set (the underlying transport/connection header requested closure).

Source

Thrown at client/rpc_stream.go:180

		// send the end of stream message
		if r.sendEOS {
			// no need to check for error
			//nolint:errcheck,gosec
			r.codec.Write(&codec.Message{
				Id:       r.id,
				Target:   r.request.Service(),
				Method:   r.request.Method(),
				Endpoint: r.request.Endpoint(),
				Type:     codec.Error,
				Error:    lastStreamResponseError,
			}, nil)
		}

		err := r.codec.Close()

		rerr := r.Error()
		if r.close && rerr == nil {
			rerr = errors.New("connection header set to close")
		}
		// release the connection
		r.release(rerr)

		return err
	}
}

View on GitHub (pinned to 24529f1404)

Solutions

  1. Ignore this error when it indicates an expected connection teardown (compare against the message or just log at debug level)
  2. Check r.Error() before Close to distinguish real stream errors from the teardown sentinel
  3. Ensure connection pooling re-establishes connections rather than treating this as fatal

Example fix

// before
if err := stream.Close(); err != nil { return err }
// after
if err := stream.Close(); err != nil && !strings.Contains(err.Error(), "connection header set to close") {
    return err
}
Defensive patterns

Strategy: type-guard

Validate before calling

// optional: inspect stream error before closing to separate real faults
serr := stream.Error() // if non-nil, real failure; Close()'s sentinel is noise

Type guard

func isConnCloseTeardown(err error) bool {
    return err != nil && strings.Contains(err.Error(), "connection header set to close")
}

Try / catch

if err := stream.Close(); err != nil && !isConnCloseTeardown(err) {
    return fmt.Errorf("stream close failed: %w", err)
}
// teardown sentinel ignored

Prevention

When it happens

Trigger: Closing a stream when r.close is true — i.e. the transport indicated the connection should be closed (connection: close semantics) — while the codec itself closed without error.

Common situations: HTTP/1.1 connections with connection: close being recycled; server asking clients not to reuse connections; pool eviction on stream teardown.

Related errors


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