Skip to content

Commit

Permalink
Add NewWireError
Browse files Browse the repository at this point in the history
Currently, only the Connect runtime can create errors that return true
when tested by `IsWireError`. However, streaming RPCs commonly indicate
partial failure by including an error code and message in their response
message. To propagate these partial failures properly, clients need a
way to construct wire errors. This commit adds `NewWireError` to satisfy
this use case.
  • Loading branch information
akshayjshah committed Jan 13, 2023
1 parent 0654729 commit b1e1dff
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 4 deletions.
19 changes: 19 additions & 0 deletions error.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,25 @@ func NewError(c Code, underlying error) *Error {
return &Error{code: c, err: underlying}
}

// NewWireError is similar to [NewError], but the resulting *Error returns true
// when tested with [IsWireError].
//
// This is useful for clients trying to propagate partial failures from
// streaming RPCs. Often, these RPCs include error information in their
// response messages (for example, [gRPC server reflection] and
// OpenTelemtetry's [OTLP]). Clients propagating these errors up the stack
// should use NewWireError to clarify that the error was explicitly sent by the
// server (rather than inferred from a lower-level networking error or
// timeout).
//
// [gRPC server reflection]: https://github.com/grpc/grpc/blob/v1.49.2/src/proto/grpc/reflection/v1alpha/reflection.proto#L132-L136
// [OTLP]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md#partial-success
func NewWireError(c Code, underlying error) *Error {
err := NewError(c, underlying)
err.wireErr = true
return err
}

// IsWireError checks whether the error was returned by the server, as opposed
// to being synthesized by the client.
//
Expand Down
3 changes: 1 addition & 2 deletions protocol_connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -943,8 +943,7 @@ func (e *connectWireError) asError() *Error {
if e.Code < minCode || e.Code > maxCode {
e.Code = CodeUnknown
}
err := NewError(e.Code, errors.New(e.Message))
err.wireErr = true
err := NewWireError(e.Code, errors.New(e.Message))
if len(e.Details) > 0 {
err.details = make([]*ErrorDetail, len(e.Details))
for i, detail := range e.Details {
Expand Down
3 changes: 1 addition & 2 deletions protocol_grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -701,8 +701,7 @@ func grpcErrorFromTrailer(bufferPool *bufferPool, protobuf Codec, trailer http.H
return errorf(CodeInternal, "gRPC protocol error: invalid error code %q", codeHeader)
}
message := grpcPercentDecode(bufferPool, trailer.Get(grpcHeaderMessage))
retErr := NewError(Code(code), errors.New(message))
retErr.wireErr = true
retErr := NewWireError(Code(code), errors.New(message))

detailsBinaryEncoded := trailer.Get(grpcHeaderDetails)
if len(detailsBinaryEncoded) > 0 {
Expand Down

0 comments on commit b1e1dff

Please sign in to comment.