2626import com .google .cloud .spanner .SpannerException .DoNotConstructDirectly ;
2727import com .google .common .base .MoreObjects ;
2828import com .google .common .base .Predicate ;
29+ import com .google .protobuf .InvalidProtocolBufferException ;
2930import com .google .rpc .ErrorInfo ;
3031import com .google .rpc .ResourceInfo ;
3132import com .google .rpc .RetryInfo ;
@@ -56,6 +57,8 @@ public final class SpannerExceptionFactory {
5657 ProtoUtils .keyForProto (ResourceInfo .getDefaultInstance ());
5758 private static final Metadata .Key <ErrorInfo > KEY_ERROR_INFO =
5859 ProtoUtils .keyForProto (ErrorInfo .getDefaultInstance ());
60+ private static final Metadata .Key <byte []> KEY_ERROR_DETAILS =
61+ Metadata .Key .of ("grpc-status-details-bin" , Metadata .BINARY_BYTE_MARSHALLER );
5962
6063 public static SpannerException newSpannerException (ErrorCode code , @ Nullable String message ) {
6164 return newSpannerException (code , message , null );
@@ -247,6 +250,10 @@ private static String formatMessage(ErrorCode code, @Nullable String message) {
247250 }
248251
249252 private static ResourceInfo extractResourceInfo (Throwable cause ) {
253+ ErrorDetails details = extractErrorDetails (cause , null );
254+ if (details != null && details .getResourceInfo () != null ) {
255+ return details .getResourceInfo ();
256+ }
250257 if (cause != null ) {
251258 Metadata trailers = Status .trailersFromThrowable (cause );
252259 if (trailers != null ) {
@@ -257,8 +264,9 @@ private static ResourceInfo extractResourceInfo(Throwable cause) {
257264 }
258265
259266 private static ErrorInfo extractErrorInfo (Throwable cause , ApiException apiException ) {
260- if (apiException != null && apiException .getErrorDetails () != null ) {
261- return apiException .getErrorDetails ().getErrorInfo ();
267+ ErrorDetails details = extractErrorDetails (cause , apiException );
268+ if (details != null && details .getErrorInfo () != null ) {
269+ return details .getErrorInfo ();
262270 }
263271 if (cause != null ) {
264272 Metadata trailers = Status .trailersFromThrowable (cause );
@@ -277,10 +285,26 @@ static ErrorDetails extractErrorDetails(Throwable cause, ApiException apiExcepti
277285 Throwable prevCause = null ;
278286 while (cause != null && cause != prevCause ) {
279287 if (cause instanceof ApiException ) {
280- return ((ApiException ) cause ).getErrorDetails ();
288+ if (((ApiException ) cause ).getErrorDetails () != null ) {
289+ return ((ApiException ) cause ).getErrorDetails ();
290+ }
281291 }
282292 if (cause instanceof SpannerException ) {
283- return ((SpannerException ) cause ).getErrorDetails ();
293+ if (((SpannerException ) cause ).getErrorDetails () != null ) {
294+ return ((SpannerException ) cause ).getErrorDetails ();
295+ }
296+ }
297+ Metadata trailers = Status .trailersFromThrowable (cause );
298+ if (trailers != null ) {
299+ byte [] bytes = trailers .get (KEY_ERROR_DETAILS );
300+ if (bytes != null ) {
301+ try {
302+ com .google .rpc .Status status = com .google .rpc .Status .parseFrom (bytes );
303+ return ErrorDetails .builder ().setRawErrorMessages (status .getDetailsList ()).build ();
304+ } catch (InvalidProtocolBufferException e ) {
305+ // ignore and continue
306+ }
307+ }
284308 }
285309 prevCause = cause ;
286310 cause = cause .getCause ();
0 commit comments