Details returns a slice of details messages attached to the status. If a detail cannot be decoded, the error is returned in place of the detail. If the detail can be decoded, the proto message returned is of the same type that was given to WithDetails().
()
| 152 | // If the detail can be decoded, the proto message returned is of the same |
| 153 | // type that was given to WithDetails(). |
| 154 | func (s *Status) Details() []any { |
| 155 | if s == nil || s.s == nil { |
| 156 | return nil |
| 157 | } |
| 158 | details := make([]any, 0, len(s.s.Details)) |
| 159 | for _, any := range s.s.Details { |
| 160 | detail, err := any.UnmarshalNew() |
| 161 | if err != nil { |
| 162 | details = append(details, err) |
| 163 | continue |
| 164 | } |
| 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)) |
| 197 | } |
| 198 | return details |
| 199 | } |
| 200 | |
| 201 | func (s *Status) String() string { |
| 202 | return fmt.Sprintf("rpc error: code = %s desc = %s", s.Code(), s.Message()) |
no outgoing calls