@@ -33,18 +33,24 @@ func EncodeError(ctx context.Context, err error) EncodedError {
3333 if cause := UnwrapOnce (err ); cause != nil {
3434 return encodeWrapper (ctx , err , cause )
3535 }
36- // Not a causer.
37- return encodeLeaf (ctx , err )
36+ return encodeLeaf (ctx , err , UnwrapMulti (err ))
3837}
3938
40- // encodeLeaf encodes a leaf error.
41- func encodeLeaf (ctx context.Context , err error ) EncodedError {
39+ // encodeLeaf encodes a leaf error. This function accepts a `causes`
40+ // argument because we encode multi-cause errors using the Leaf
41+ // protobuf. This was done to enable backwards compatibility when
42+ // introducing this functionality since the Wrapper type already has a
43+ // required single `cause` field.
44+ func encodeLeaf (ctx context.Context , err error , causes []error ) EncodedError {
4245 var msg string
4346 var details errorspb.EncodedErrorDetails
4447
4548 if e , ok := err .(* opaqueLeaf ); ok {
4649 msg = e .msg
4750 details = e .details
51+ } else if e , ok := err .(* opaqueLeafCauses ); ok {
52+ msg = e .msg
53+ details = e .details
4854 } else {
4955 details .OriginalTypeName , details .ErrorTypeMark .FamilyName , details .ErrorTypeMark .Extension = getTypeDetails (err , false /*onlyFamily*/ )
5056
@@ -74,11 +80,21 @@ func encodeLeaf(ctx context.Context, err error) EncodedError {
7480 details .FullDetails = encodeAsAny (ctx , err , payload )
7581 }
7682
83+ var cs []* EncodedError
84+ if len (causes ) > 0 {
85+ cs = make ([]* EncodedError , len (causes ))
86+ for i , ee := range causes {
87+ ee := EncodeError (ctx , ee )
88+ cs [i ] = & ee
89+ }
90+ }
91+
7792 return EncodedError {
7893 Error : & errorspb.EncodedError_Leaf {
7994 Leaf : & errorspb.EncodedErrorLeaf {
80- Message : msg ,
81- Details : details ,
95+ Message : msg ,
96+ Details : details ,
97+ MultierrorCauses : cs ,
8298 },
8399 },
84100 }
@@ -207,6 +223,8 @@ func getTypeDetails(
207223 switch t := err .(type ) {
208224 case * opaqueLeaf :
209225 return t .details .OriginalTypeName , t .details .ErrorTypeMark .FamilyName , t .details .ErrorTypeMark .Extension
226+ case * opaqueLeafCauses :
227+ return t .details .OriginalTypeName , t .details .ErrorTypeMark .FamilyName , t .details .ErrorTypeMark .Extension
210228 case * opaqueWrapper :
211229 return t .details .OriginalTypeName , t .details .ErrorTypeMark .FamilyName , t .details .ErrorTypeMark .Extension
212230 }
@@ -310,6 +328,28 @@ type LeafEncoder = func(ctx context.Context, err error) (msg string, safeDetails
310328// registry for RegisterLeafEncoder.
311329var leafEncoders = map [TypeKey ]LeafEncoder {}
312330
331+ // RegisterMultiCauseEncoder can be used to register new multi-cause
332+ // error types to the library. Registered types will be encoded using
333+ // their own Go type when an error is encoded. Multi-cause wrappers
334+ // that have not been registered will be encoded using the
335+ // opaqueWrapper type.
336+ func RegisterMultiCauseEncoder (theType TypeKey , encoder MultiCauseEncoder ) {
337+ // This implementation is a simple wrapper around `LeafEncoder`
338+ // because we implemented multi-cause error wrapper encoding into a
339+ // `Leaf` instead of a `Wrapper` for smoother backwards
340+ // compatibility support. Exposing this detail to consumers of the
341+ // API is confusing and hence avoided. The causes of the error are
342+ // encoded separately regardless of this encoder's implementation.
343+ RegisterLeafEncoder (theType , encoder )
344+ }
345+
346+ // MultiCauseEncoder is to be provided (via RegisterMultiCauseEncoder
347+ // above) by additional multi-cause wrapper types not yet known to this
348+ // library. The encoder will automatically extract and encode the
349+ // causes of this error by calling `Unwrap()` and expecting a slice of
350+ // errors.
351+ type MultiCauseEncoder = func (ctx context.Context , err error ) (msg string , safeDetails []string , payload proto.Message )
352+
313353// RegisterWrapperEncoder can be used to register new wrapper types to
314354// the library. Registered wrappers will be encoded using their own
315355// Go type when an error is encoded. Wrappers that have not been
0 commit comments