Skip to content

Error metadata is sent as trailers instead of headers in unary RPCs #850

@frozenbonito

Description

@frozenbonito

Describe the bug

When setting metadata on an error, the metadata is sent as a trailer even for Unary RPCs.

According to the documentation for Error.Meta, I expected the metadata to be sent as headers:

Metadata attached to errors returned by unary handlers is always sent as HTTP headers, regardless of the protocol.

To Reproduce

A reproduction repository is available here:
https://github.com/frozenbonito/connect-error-metadata

The main.go file starts a Connect server that returns an error with attached metadata, then uses a grpc-go client to call it and inspect the headers and trailers.
For comparison, it also includes a similar grpc-go server and performs the same inspection.

$ git clone https://github.com/frozenbonito/connect-error-metadata
$ cd connect-error-metadata/
$ go run main.go
Connect
rpc error: code = Unimplemented desc = unimplemented
header: map[content-type:[application/grpc] date:[Thu, 05 Jun 2025 01:19:53 GMT] grpc-accept-encoding:[gzip]]
trailer: map[custom-key:[value]]
-----------------
gRPC
rpc error: code = Unimplemented desc = unimplemented
header: map[content-type:[application/grpc] custom-key:[value]]
trailer: map[]

custom-key is the metadata added by the handler.

Environment (please complete the following information):

  • connect-go version or commit: v1.18.1
  • go version: go version go1.24.3 linux/amd64
  • your complete go.mod:
module github.com/frozenbonito/connect-error-metadata

go 1.24.3

require (
	connectrpc.com/connect v1.18.1
	golang.org/x/net v0.35.0
	google.golang.org/grpc v1.72.2
	google.golang.org/protobuf v1.36.6
)

require (
	golang.org/x/sys v0.30.0 // indirect
	golang.org/x/text v0.22.0 // indirect
	google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
)

Additional context
As demonstrated in the reproduction code, grpc-go sends metadata as headers even for error responses.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions