Skip to content

Conversation

@psainics
Copy link
Contributor

@psainics psainics commented Feb 27, 2025

ErrorDetailsProvider - BigTable [Source|Sink] plugin

Jira : PLUGIN-1870

Description

Implement Program Failure Exception Handling in BigTable Source/Sink plugin to catch known errors.

Code change

  • Added BigtableErrorDetailsProvider.java
  • Modified BigtableSink.java
  • Modified BigtableSource.java
  • Modified GCPErrorDetailsProvider.java
  • Modified GCPUtils.java

Tests

  • Using a read only key

image

[
  {
    "stageName": "Bigtable",
    "errorCategory": "Plugin-'Bigtable'",
    "errorReason": "403 PERMISSION_DENIED: Access denied. Missing IAM permission: bigtable.tables.mutateRows.. Please check you have permission to access this resource. For more details, see https://cloud.google.com/bigtable/docs/status-codes.",
    "errorMessage": "com.google.bigtable.repackaged.io.grpc.StatusRuntimeException: [ErrorCode='403'] PERMISSION_DENIED: Access denied. Missing IAM permission: bigtable.tables.mutateRows.",
    "errorType": "USER",
    "dependency": "true",
    "errorCodeType": "HTTP",
    "errorCode": "403",
    "supportedDocumentationUrl": "https://cloud.google.com/spanner/docs/error-codes"
  }
]
2025-04-16 13:29:27,344 - ERROR [grpc-default-executor-0:c.g.b.r.c.g.c.b.g.a.AbstractRetryingOperation@158] - Could not complete RPC. Failure #0, got: Status{code=PERMISSION_DENIED, description=Access denied. Missing IAM permission: bigtable.tables.mutateRows., cause=null} on channel 97.
Trailers: Metadata(endpoint-load-metrics-bin=MRsYUnQy1KxAOVU9Akm2WNk/SWDFkcwlidY/,grpc-server-stats-bin=AAAm1yICAAAAAA,pc-high-bwd-bin=S2dJWURn,bigtable-channel-id=97)
2025-04-16 13:29:27,352 - WARN  [Executor task launch worker for task 0.0 in stage 0.0 (TID 0):c.g.c.b.h.BigtableBufferedMutator@131] - Exception occurred in BufferedMutator
com.google.bigtable.repackaged.io.grpc.StatusRuntimeException: PERMISSION_DENIED: Access denied. Missing IAM permission: bigtable.tables.mutateRows.
	at com.google.bigtable.repackaged.io.grpc.Status.asRuntimeException(Status.java:524)
	at com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.async.AbstractRetryingOperation.onError(AbstractRetryingOperation.java:214)
	at com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.async.AbstractRetryingOperation.onClose(AbstractRetryingOperation.java:177)
	at com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.async.ThrottlingClientInterceptor$1$1.onClose(ThrottlingClientInterceptor.java:131)
	at com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.io.ChannelPool$InstrumentedChannel$2.onClose(ChannelPool.java:212)
	at com.google.bigtable.repackaged.io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	at com.google.bigtable.repackaged.io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
	at com.google.bigtable.repackaged.io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
	at com.google.bigtable.repackaged.io.grpc.census.CensusStatsModule$StatsClientInterceptor$1$1.onClose(CensusStatsModule.java:701)
	at com.google.bigtable.repackaged.io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	at com.google.bigtable.repackaged.io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
	at com.google.bigtable.repackaged.io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
	at com.google.bigtable.repackaged.io.grpc.census.CensusTracingModule$TracingClientInterceptor$1$1.onClose(CensusTracingModule.java:399)
	at com.google.bigtable.repackaged.io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:426)
	at com.google.bigtable.repackaged.io.grpc.internal.ClientCallImpl.access$500(ClientCallImpl.java:66)
	at com.google.bigtable.repackaged.io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:689)
	at com.google.bigtable.repackaged.io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$900(ClientCallImpl.java:577)
	at com.google.bigtable.repackaged.io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:751)
	at com.google.bigtable.repackaged.io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:740)
	at com.google.bigtable.repackaged.io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
	at com.google.bigtable.repackaged.io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:750)
2025-04-16 13:30:44,670 - ERROR [Executor task launch worker for task 0.0 in stage 0.0 (TID 0):o.a.s.u.Utils@98] - Aborting task
io.cdap.cdap.api.exception.WrappedStageException: Stage 'Bigtable' encountered : io.cdap.cdap.api.exception.ProgramFailureException: com.google.bigtable.repackaged.io.grpc.StatusRuntimeException: [ErrorCode='403'] PERMISSION_DENIED: Access denied. Missing IAM permission: bigtable.tables.mutateRows.
	at io.cdap.cdap.etl.common.ErrorDetails.handleException(ErrorDetails.java:77)
	at io.cdap.cdap.etl.spark.io.StageTrackingRecordWriter.close(StageTrackingRecordWriter.java:67)
	at org.apache.spark.internal.io.HadoopMapReduceWriteConfigUtil.closeWriter(SparkHadoopWriter.scala:373)
	at org.apache.spark.internal.io.SparkHadoopWriter$.$anonfun$executeTask$1(SparkHadoopWriter.scala:145)
	at org.apache.spark.util.Utils$.tryWithSafeFinallyAndFailureCallbacks(Utils.scala:1538)
	at org.apache.spark.internal.io.SparkHadoopWriter$.executeTask(SparkHadoopWriter.scala:135)
	at org.apache.spark.internal.io.SparkHadoopWriter$.$anonfun$write$1(SparkHadoopWriter.scala:88)
	at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:90)
	at org.apache.spark.scheduler.Task.run(Task.scala:136)
	at org.apache.spark.executor.Executor$TaskRunner.$anonfun$run$3(Executor.scala:548)
	at org.apache.spark.util.Utils$.tryWithSafeFinally(Utils.scala:1504)
	at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:551)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:750)
Caused by: io.cdap.cdap.api.exception.ProgramFailureException: com.google.bigtable.repackaged.io.grpc.StatusRuntimeException: [ErrorCode='403'] PERMISSION_DENIED: Access denied. Missing IAM permission: bigtable.tables.mutateRows.
	at io.cdap.cdap.api.exception.ProgramFailureException$Builder.build(ProgramFailureException.java:229)
	at io.cdap.cdap.api.exception.ErrorUtils.getProgramFailureException(ErrorUtils.java:198)
	at io.cdap.plugin.gcp.bigtable.common.BigtableErrorDetailsProvider.getProgramFailureExceptionFromBigTableException(BigtableErrorDetailsProvider.java:110)
	at io.cdap.plugin.gcp.bigtable.common.BigtableErrorDetailsProvider.getExceptionDetails(BigtableErrorDetailsProvider.java:87)
	at io.cdap.cdap.etl.common.ErrorDetails.handleException(ErrorDetails.java:75)
	... 14 common frames omitted
Caused by: com.google.bigtable.repackaged.io.grpc.StatusRuntimeException: PERMISSION_DENIED: Access denied. Missing IAM permission: bigtable.tables.mutateRows.
	at com.google.bigtable.repackaged.io.grpc.Status.asRuntimeException(Status.java:524)
	at com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.async.AbstractRetryingOperation.onError(AbstractRetryingOperation.java:214)
	at com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.async.AbstractRetryingOperation.onClose(AbstractRetryingOperation.java:177)
	at com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.async.ThrottlingClientInterceptor$1$1.onClose(ThrottlingClientInterceptor.java:131)
	at com.google.bigtable.repackaged.com.google.cloud.bigtable.grpc.io.ChannelPool$InstrumentedChannel$2.onClose(ChannelPool.java:212)
	at com.google.bigtable.repackaged.io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	at com.google.bigtable.repackaged.io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
	at com.google.bigtable.repackaged.io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
	at com.google.bigtable.repackaged.io.grpc.census.CensusStatsModule$StatsClientInterceptor$1$1.onClose(CensusStatsModule.java:701)
	at com.google.bigtable.repackaged.io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	at com.google.bigtable.repackaged.io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
	at com.google.bigtable.repackaged.io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
	at com.google.bigtable.repackaged.io.grpc.census.CensusTracingModule$TracingClientInterceptor$1$1.onClose(CensusTracingModule.java:399)
	at com.google.bigtable.repackaged.io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:426)
	at com.google.bigtable.repackaged.io.grpc.internal.ClientCallImpl.access$500(ClientCallImpl.java:66)
	at com.google.bigtable.repackaged.io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:689)
	at com.google.bigtable.repackaged.io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$900(ClientCallImpl.java:577)
	at com.google.bigtable.repackaged.io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:751)
	at com.google.bigtable.repackaged.io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:740)
	at com.google.bigtable.repackaged.io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
	at com.google.bigtable.repackaged.io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
	... 3 common frames omitted

@psainics psainics added the build Trigger unit test build label Feb 27, 2025
@psainics psainics self-assigned this Feb 27, 2025
@psainics psainics changed the title Fem/bigtable [PLUGIN-1870] Add BigtableErrorDetailsProvider Mar 5, 2025
@AnkitCLI AnkitCLI force-pushed the fem/bigtable branch 5 times, most recently from 04321a2 to 3f2ead3 Compare April 8, 2025 17:55
@AnkitCLI AnkitCLI marked this pull request as ready for review April 8, 2025 17:56
@AnkitCLI AnkitCLI requested a review from itsankit-google April 9, 2025 06:12
Copy link
Contributor

@itsankit-google itsankit-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls add screenshot of RPC code returned by BigTableAPI client.

@psainics psainics force-pushed the fem/bigtable branch 2 times, most recently from 77e903d to 45e50e2 Compare April 16, 2025 08:04
Comment on lines 42 to 63
private static final String ERROR_MESSAGE_FORMAT = "Error occurred in the phase: '%s'. Error message: %s";

static Map<Status.Code, Integer> actionErrorMap = new HashMap<>();

static {
actionErrorMap.put(Status.Code.CANCELLED, 499);
actionErrorMap.put(Status.Code.UNKNOWN, 500);
actionErrorMap.put(Status.Code.INVALID_ARGUMENT, 400);
actionErrorMap.put(Status.Code.DEADLINE_EXCEEDED, 504);
actionErrorMap.put(Status.Code.NOT_FOUND, 404);
actionErrorMap.put(Status.Code.ALREADY_EXISTS, 409);
actionErrorMap.put(Status.Code.PERMISSION_DENIED, 403);
actionErrorMap.put(Status.Code.UNAUTHENTICATED, 401);
actionErrorMap.put(Status.Code.RESOURCE_EXHAUSTED, 429);
actionErrorMap.put(Status.Code.FAILED_PRECONDITION, 400);
actionErrorMap.put(Status.Code.ABORTED, 409);
actionErrorMap.put(Status.Code.OUT_OF_RANGE, 400);
actionErrorMap.put(Status.Code.UNIMPLEMENTED, 501);
actionErrorMap.put(Status.Code.INTERNAL, 500);
actionErrorMap.put(Status.Code.UNAVAILABLE, 503);
actionErrorMap.put(Status.Code.DATA_LOSS, 500);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is duplicated, can we move this to Util class and use it everywhere?

private static final String ERROR_MESSAGE_FORMAT = "Error occurred in the phase: '%s'. Error message: %s";
static Map<ErrorCode, Integer> actionErrorMap = new HashMap<>();
static {
actionErrorMap.put(ErrorCode.CANCELLED, 499);
actionErrorMap.put(ErrorCode.UNKNOWN, 500);
actionErrorMap.put(ErrorCode.INVALID_ARGUMENT, 400);
actionErrorMap.put(ErrorCode.DEADLINE_EXCEEDED, 504);
actionErrorMap.put(ErrorCode.NOT_FOUND, 404);
actionErrorMap.put(ErrorCode.ALREADY_EXISTS, 409);
actionErrorMap.put(ErrorCode.PERMISSION_DENIED, 403);
actionErrorMap.put(ErrorCode.UNAUTHENTICATED, 401);
actionErrorMap.put(ErrorCode.RESOURCE_EXHAUSTED, 429);
actionErrorMap.put(ErrorCode.FAILED_PRECONDITION, 400);
actionErrorMap.put(ErrorCode.ABORTED, 409);
actionErrorMap.put(ErrorCode.OUT_OF_RANGE, 400);
actionErrorMap.put(ErrorCode.UNIMPLEMENTED, 501);
actionErrorMap.put(ErrorCode.INTERNAL, 500);
actionErrorMap.put(ErrorCode.UNAVAILABLE, 503);
actionErrorMap.put(ErrorCode.DATA_LOSS, 500);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, moved the code to common place.

Comment on lines 86 to 87
if (innerCause instanceof StatusRuntimeException) {
return getProgramFailureExceptionFromBigTableException((StatusRuntimeException) innerCause);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for every innerCause we can just call this.getExceptionDetails(innerCause, errorContext), if it is not null, we can continue in the loop otherwise return the exception?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now calling return this.getExceptionDetails((Exception) innerCause, errorContext), i don't get what is meant by if not null we can continue ?

@psainics
Copy link
Contributor Author

BigTable [GRPC = 7]

image

[
  {
    "stageName": "Bigtable",
    "errorCategory": "Plugin-'Bigtable'",
    "errorReason": "403 PERMISSION_DENIED: Access denied. Missing IAM permission: bigtable.tables.mutateRows.. Please check you have permission to access this resource. For more details, see https://cloud.google.com/bigtable/docs/status-codes.",
    "errorMessage": "com.google.bigtable.repackaged.io.grpc.StatusRuntimeException: [ErrorCode='403'] PERMISSION_DENIED: Access denied. Missing IAM permission: bigtable.tables.mutateRows.",
    "errorType": "USER",
    "dependency": "true",
    "errorCodeType": "HTTP",
    "errorCode": "403",
    "supportedDocumentationUrl": "https://cloud.google.com/bigtable/docs/status-codes"
  }
]

Spanner [GRPC = 7]

image

[
  {
    "stageName": "Spanner2",
    "errorCategory": "Plugin-\\u0027Spanner2\\u0027",
    "errorReason": "403 PERMISSION_DENIED: io.grpc.StatusRuntimeException: PERMISSION_DENIED: Caller is missing IAM permission spanner.databases.updateDdl on resource projects/cdf-entcon/instances/e2e-20231011-09-35-048376917/databases/e2e-source-db-a8e7a64a-c.. Please check you have permission to access this resource. For more details, see https://cloud.google.com/spanner/docs/error-codes.",
    "errorMessage": "com.google.cloud.spanner.SpannerException: [ErrorCode\\u003d\\u0027403\\u0027] PERMISSION_DENIED: io.grpc.StatusRuntimeException: PERMISSION_DENIED: Caller is missing IAM permission spanner.databases.updateDdl on resource projects/cdf-entcon/instances/e2e-20231011-09-35-048376917/databases/e2e-source-db-a8e7a64a-c.",
    "errorType": "USER",
    "dependency": "true",
    "errorCodeType": "HTTP",
    "errorCode": "403",
    "supportedDocumentationUrl": "https://cloud.google.com/spanner/docs/error-codes"
  }
]

Comment on lines 43 to 81
public static final Map<Integer, Integer> GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP = new HashMap<>();

static {
// https://github.com/grpc/grpc/blob/master/doc/statuscodes.md
// OK 0 <--> HTTP 200 (OK)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(0, 200);
// CANCELLED 1 <--> HTTP 499 (Client Closed Request)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(1, 499);
// UNKNOWN 2 <--> HTTP 500 (Internal Server Error)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(2, 500);
// INVALID_ARGUMENT 3 <--> HTTP 400 (Bad Request)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(3, 400);
// DEADLINE_EXCEEDED 4 <--> HTTP 504 (Gateway Timeout)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(4, 504);
// NOT_FOUND 5 <--> HTTP 404 (Not Found)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(5, 404);
// ALREADY_EXISTS 6 <--> HTTP 409 (Conflict)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(6, 409);
// PERMISSION_DENIED 7 <--> HTTP 403 (Forbidden)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(7, 403);
// RESOURCE_EXHAUSTED 8 <--> HTTP 429 (Too Many Requests)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(8, 429);
// FAILED_PRECONDITION 9 <--> HTTP 400 (Bad Request)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(9, 400);
// ABORTED 10 <--> HTTP 409 (Conflict)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(10, 409);
// OUT_OF_RANGE 11 <--> HTTP 400 (Bad Request)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(11, 400);
// UNIMPLEMENTED 12 <--> HTTP 501 (Not Implemented)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(12, 501);
// INTERNAL 13 <--> HTTP 500 (Internal Server Error)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(13, 500);
// UNAVAILABLE 14 <--> HTTP 503 (Service Unavailable)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(14, 503);
// DATA_LOSS 15 <--> HTTP 500 (Internal Server Error)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(15, 500);
// UNAUTHENTICATED 16 <--> HTTP 401 (Unauthorized)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(16, 401);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please convert it into a static immutable map as done in reference shared in above comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// https://github.com/grpc/grpc/blob/master/doc/statuscodes.md
public static final Map<Integer, Integer> GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP = Collections.unmodifiableMap(
      new HashMap<Integer, Integer>() {{
        put(3, 400); // INVALID_ARGUMENT <--> HTTP 400 (Bad Request)
        put(4, 504); // DEADLINE_EXCEEDED <--> HTTP 504 (Gateway Timeout)
        put(5, 404); // NOT_FOUND <--> HTTP 404 (Not Found)
        put(6, 409); // ALREADY_EXISTS <--> HTTP 409 (Conflict)
        put(7, 403); // PERMISSION_DENIED <--> HTTP 403 (Forbidden)
        put(8, 429); // RESOURCE_EXHAUSTED <--> HTTP 429 (Too Many Requests)
        put(9, 400); // FAILED_PRECONDITION <--> HTTP 400 (Bad Request)
        put(10, 409); // ABORTED <--> HTTP 409 (Conflict)
        put(11, 400); // OUT_OF_RANGE <--> HTTP 400 (Bad Request)
        put(12, 501); // UNIMPLEMENTED <--> HTTP 501 (Not Implemented)
        put(13, 500); // INTERNAL <--> HTTP 500 (Internal Server Error)
        put(14, 503); // UNAVAILABLE <--> HTTP 503 (Service Unavailable)
        put(15, 500); // DATA_LOSS <--> HTTP 500 (Internal Server Error)
        put(16, 401); // UNAUTHENTICATED <--> HTTP 401 (Unauthorized)
}});

// UNAUTHENTICATED 16 <--> HTTP 401 (Unauthorized)
GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(16, 401);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove empty line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed!

import io.cdap.plugin.gcp.common.GCPErrorDetailsProvider;
import io.cdap.plugin.gcp.common.GCPErrorDetailsProviderUtil;
import io.cdap.plugin.gcp.common.GCPUtils;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove empty line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed!

List<Throwable> innerCauses = r.getCauses();
for (Throwable innerCause : innerCauses) {
if (innerCause instanceof Exception) {
return this.getExceptionDetails((Exception) innerCause, errorContext);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure that all innerCauses will contain the actual exception we are looking for?

It is still possible that innerCauses[0] returns null and does not contain StatusRuntimeException, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed to Exception so that even the parent class can handle if there is a known error,
innerCause being null won't cause an issue as we check with instanceof Exception, it will be skipped anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was not about innerCause being null, this.getExceptionDetails((Exception) innerCause, errorContext) can still return null and loop will break and we will not traverse forward.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, got it, added a null check.

if (innerCause instanceof Exception) {
  ProgramFailureException pfe = this.getExceptionDetails((Exception) innerCause, errorContext);
  if (pfe != null) {
    return pfe;
  }
}


public static ProgramFailureException getProgramFailureExceptionByGrpcStatusCode(int grpcErrorCodeValue,
String grpcErrorReason, String grpcErrorMessage, String supportedDocUrl, Exception se) {
int httpStatusCode = GCPErrorDetailsProviderUtil.GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.get(grpcErrorCodeValue);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the value is not found in map use 500.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

actionErrorPair != null ? actionErrorPair.getErrorType() : ErrorType.UNKNOWN, true, ErrorCodeType.HTTP,
String.valueOf(httpStatusCode), supportedDocUrl, se);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: remove empty line

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@psainics psainics requested a review from itsankit-google May 19, 2025 06:14
@psainics psainics merged commit d991ce7 into data-integrations:develop May 20, 2025
16 checks passed
@psainics psainics deleted the fem/bigtable branch May 20, 2025 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build Trigger unit test build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants