Skip to content

Commit 6b0b291

Browse files
zasweqatollena
andauthored
status: fix panic when servers return a wrapped error with status OK (#6374) (#6430)
Co-authored-by: Antoine Tollenaere <[email protected]>
1 parent ed56401 commit 6b0b291

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

status/status.go

+25-4
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,18 @@ func FromProto(s *spb.Status) *Status {
7777
// FromError returns a Status representation of err.
7878
//
7979
// - If err was produced by this package or implements the method `GRPCStatus()
80-
// *Status`, or if err wraps a type satisfying this, the appropriate Status is
81-
// returned. For wrapped errors, the message returned contains the entire
82-
// err.Error() text and not just the wrapped status.
80+
// *Status` and `GRPCStatus()` does not return nil, or if err wraps a type
81+
// satisfying this, the Status from `GRPCStatus()` is returned. For wrapped
82+
// errors, the message returned contains the entire err.Error() text and not
83+
// just the wrapped status. In that case, ok is true.
8384
//
84-
// - If err is nil, a Status is returned with codes.OK and no message.
85+
// - If err is nil, a Status is returned with codes.OK and no message, and ok
86+
// is true.
87+
//
88+
// - If err implements the method `GRPCStatus() *Status` and `GRPCStatus()`
89+
// returns nil (which maps to Codes.OK), or if err wraps a type
90+
// satisfying this, a Status is returned with codes.Unknown and err's
91+
// Error() message, and ok is false.
8592
//
8693
// - Otherwise, err is an error not compatible with this package. In this
8794
// case, a Status is returned with codes.Unknown and err's Error() message,
@@ -92,10 +99,24 @@ func FromError(err error) (s *Status, ok bool) {
9299
}
93100
type grpcstatus interface{ GRPCStatus() *Status }
94101
if gs, ok := err.(grpcstatus); ok {
102+
if gs.GRPCStatus() == nil {
103+
// Error has status nil, which maps to codes.OK. There
104+
// is no sensible behavior for this, so we turn it into
105+
// an error with codes.Unknown and discard the existing
106+
// status.
107+
return New(codes.Unknown, err.Error()), false
108+
}
95109
return gs.GRPCStatus(), true
96110
}
97111
var gs grpcstatus
98112
if errors.As(err, &gs) {
113+
if gs.GRPCStatus() == nil {
114+
// Error wraps an error that has status nil, which maps
115+
// to codes.OK. There is no sensible behavior for this,
116+
// so we turn it into an error with codes.Unknown and
117+
// discard the existing status.
118+
return New(codes.Unknown, err.Error()), false
119+
}
99120
p := gs.GRPCStatus().Proto()
100121
p.Message = err.Error()
101122
return status.FromProto(p), true

status/status_test.go

+27
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,33 @@ func (s) TestFromErrorWrapped(t *testing.T) {
202202
}
203203
}
204204

205+
type customErrorNilStatus struct {
206+
}
207+
208+
func (c customErrorNilStatus) Error() string {
209+
return "test"
210+
}
211+
212+
func (c customErrorNilStatus) GRPCStatus() *Status {
213+
return nil
214+
}
215+
216+
func (s) TestFromErrorImplementsInterfaceReturnsOKStatus(t *testing.T) {
217+
err := customErrorNilStatus{}
218+
s, ok := FromError(err)
219+
if ok || s.Code() != codes.Unknown || s.Message() != err.Error() {
220+
t.Fatalf("FromError(%v) = %v, %v; want <Code()=%s, Message()=%q, Err()!=nil>, true", err, s, ok, codes.Unknown, err.Error())
221+
}
222+
}
223+
224+
func (s) TestFromErrorImplementsInterfaceReturnsOKStatusWrapped(t *testing.T) {
225+
err := fmt.Errorf("wrapping: %w", customErrorNilStatus{})
226+
s, ok := FromError(err)
227+
if ok || s.Code() != codes.Unknown || s.Message() != err.Error() {
228+
t.Fatalf("FromError(%v) = %v, %v; want <Code()=%s, Message()=%q, Err()!=nil>, true", err, s, ok, codes.Unknown, err.Error())
229+
}
230+
}
231+
205232
func (s) TestFromErrorImplementsInterfaceWrapped(t *testing.T) {
206233
const code, message = codes.Internal, "test description"
207234
err := fmt.Errorf("wrapped error: %w", customError{Code: code, Message: message})

0 commit comments

Comments
 (0)