@@ -149,6 +149,8 @@ func (s *Status) WithDetails(details ...protoadapt.MessageV1) (*Status, error) {
149
149
150
150
// Details returns a slice of details messages attached to the status.
151
151
// If a detail cannot be decoded, the error is returned in place of the detail.
152
+ // If the detail can be decoded, the proto message returned is of the same
153
+ // type that was given to WithDetails().
152
154
func (s * Status ) Details () []any {
153
155
if s == nil || s .s == nil {
154
156
return nil
@@ -160,7 +162,38 @@ func (s *Status) Details() []any {
160
162
details = append (details , err )
161
163
continue
162
164
}
163
- details = append (details , detail )
165
+ // The call to MessageV1Of is required to unwrap the proto message if
166
+ // it implemented only the MessageV1 API. The proto message would have
167
+ // been wrapped in a V2 wrapper in Status.WithDetails. V2 messages are
168
+ // added to a global registry used by any.UnmarshalNew().
169
+ // MessageV1Of has the following behaviour:
170
+ // 1. If the given message is a wrapped MessageV1, it returns the
171
+ // unwrapped value.
172
+ // 2. If the given message already implements MessageV1, it returns it
173
+ // as is.
174
+ // 3. Else, it wraps the MessageV2 in a MessageV1 wrapper.
175
+ //
176
+ // Since the Status.WithDetails() API only accepts MessageV1, calling
177
+ // MessageV1Of ensures we return the same type that was given to
178
+ // WithDetails:
179
+ // * If the give type implemented only MessageV1, the unwrapping from
180
+ // point 1 above will restore the type.
181
+ // * If the given type implemented both MessageV1 and MessageV2, point 2
182
+ // above will ensure no wrapping is performed.
183
+ // * If the given type implemented only MessageV2 and was wrapped using
184
+ // MessageV1Of before passing to WithDetails(), it would be unwrapped
185
+ // in WithDetails by calling MessageV2Of(). Point 3 above will ensure
186
+ // that the type is wrapped in a MessageV1 wrapper again before
187
+ // returning. Note that protoc-gen-go doesn't generate code which
188
+ // implements ONLY MessageV2 at the time of writing.
189
+ //
190
+ // NOTE: Status details can also be added using the FromProto method.
191
+ // This could theoretically allow passing a Detail message that only
192
+ // implements the V2 API. In such a case the message will be wrapped in
193
+ // a MessageV1 wrapper when fetched using Details().
194
+ // Since protoc-gen-go generates only code that implements both V1 and
195
+ // V2 APIs for backward compatibility, this is not a concern.
196
+ details = append (details , protoadapt .MessageV1Of (detail ))
164
197
}
165
198
return details
166
199
}
0 commit comments