googleapis / googleapis/google-cloud-java
[java-spanner] NullPointerException occurring in HttpJsonSpannerStub.batchWriteCallable() when handling an error status response.
- Lenguaje dominante
- Java
- Estrellas
- 2.1k
- Forks
- 1.2k
- Merge medio
- 1 d 23 h
- PR fusionados (30 d)
- 154
Descripción
I'd like to report a `NullPointerException` in `HttpJsonSpannerStub` generated by gapic-generator. I understand the code is not intended for end-user use, but I'm reporting it in case others encounter similar issues
#### Environment details
* OS type and version: macOS 15.3
* Java version: 11
* version(s): google-cloud-spanner 6.86.6
#### Steps to reproduce
1. Create a Spanner table with `CREATE TABLE table1 (k STRING(100), v INT64) PRIMARY KEY (k)`.
2. Add a row with the key `k` as "k1".
3. Run the following code which writes a row with `k` as "k1". This will result in an error status response from Cloud Spanner.
An exception with an appropriate error message, such as "Row [k1] in table table1 already exists," is expected. However, a NullPointerException is thrown instead.
#### Code example
```java
import com.google.api.gax.rpc.ServerStream;
import com.google.api.gax.rpc.ServerStreamingCallable;
import com.google.cloud.spanner.v1.stub.SpannerStub;
import com.google.cloud.spanner.v1.stub.SpannerStubSettings;
import com.google.protobuf.ListValue;
import com.google.protobuf.Value;
import com.google.spanner.v1.*;
import java.io.IOException;
public class SpannerHttpJsonStubMain {
public static void main(String[] args) throws IOException {
SpannerStubSettings stubSettings = SpannerStubSettings.newHttpJsonBuilder().build();
try (SpannerStub stub = stubSettings.createStub()) {
Session session = stub.createSessionCallable()
.call(CreateSessionRequest.newBuilder()
.setDatabase("projects//instances/spanner-1/databases/db-1")
.build());
BatchWriteRequest request = BatchWriteRequest.newBuilder()
.setSession(session.getName())
.addMutationGroups(BatchWriteRequest.MutationGroup.newBuilder()
.addMutations(Mutation.newBuilder()
.setInsert(Mutation.Write.newBuilder()
// SCHEMA: CREATE TABLE table1 (k STRING(100), v INT64) PRIMARY KEY (k)
.setTable("table1")
.addColumns("k")
.addColumns("v")
// The key "k1" already exists in the table. Therefore, this request will result in an error
// response.
.addValues(ListValue.newBuilder()
.addValues(Value.newBuilder().setStringValue("k1"))
.addValues(Value.newBuilder().setStringValue("1"))))))
.build();
ServerStreamingCallable callable = stub.batchWriteCallable();
ServerStream responseStream = callable.call(request);
for (BatchWriteResponse response : responseStream) {
System.out.println("response = " + response);
}
}
}
}
```
#### Stack trace
The code was run with the JVM option `-Djava.util.logging.config.file=logging.properties` to enable HTTP transport debug logging. The logging.properties file is [here](https://github.com/baeminbo/dataflow-pipelines/blob/master/spanner-study/logging.properties). The output shows that parsing `DebugInfo` failed because `TypedRegistry` was `null` in some location
```
... skipped ...
Feb 11, 2025 11:21:51 PM com.google.api.client.http.HttpResponse
CONFIG: -------------- RESPONSE --------------
HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
Transfer-Encoding: chunked
Server: ESF
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
Server-Timing: gfet4t7; dur=148
Content-Encoding: gzip
Vary: Origin
Vary: X-Origin
Vary: Referer
X-XSS-Protection: 0
Date: Wed, 12 Feb 2025 07:21:51 GMT
Content-Type: application/json; charset=UTF-8
Feb 11, 2025 11:21:51 PM com.google.api.client.util.LoggingByteArrayOutputStream close
CONFIG: Total: 254 bytes
Feb 11, 2025 11:21:51 PM com.google.api.client.util.LoggingByteArrayOutputStream close
CONFIG: [{
"indexes": [
0
],
"status": {
"code": 6,
"message": "Row [k1] in table table1 already exists",
"details": [
{
"@type": "type.googleapis.com/google.rpc.DebugInfo",
"detail": "table1(k1)"
}
]
}
}
]
Exception in thread "main" com.google.api.gax.rpc.CancelledException: Exception in message delivery
at com.google.api.gax.rpc.ApiExceptionFactory.createException(ApiExceptionFactory.java:48)
at com.google.api.gax.httpjson.HttpJsonApiExceptionFactory.createApiException(HttpJsonApiExceptionFactory.java:76)
at com.google.api.gax.httpjson.HttpJsonApiExceptionFactory.create(HttpJsonApiExceptionFactory.java:58)
at com.google.api.gax.httpjson.HttpJsonExceptionResponseObserver.onErrorImpl(HttpJsonExceptionResponseObserver.java:82)
at com.google.api.gax.rpc.StateCheckingResponseObserver.onError(StateCheckingResponseObserver.java:84)
at com.google.api.gax.httpjson.HttpJsonDirectStreamController$ResponseObserverAdapter.onClose(HttpJsonDirectStreamController.java:125)
at com.google.api.gax.httpjson.HttpJsonClientCallImpl$OnCloseNotificationTask.call(HttpJsonClientCallImpl.java:551)
at com.google.api.gax.httpjson.HttpJsonClientCallImpl.notifyListeners(HttpJsonClientCallImpl.java:390)
at com.google.api.gax.httpjson.HttpJsonClientCallImpl.deliver(HttpJsonClientCallImpl.java:317)
at com.google.api.gax.httpjson.HttpJsonClientCallImpl.setResult(HttpJsonClientCallImpl.java:163)
at com.google.api.gax.httpjson.HttpRequestRunnable.run(HttpRequestRunnable.java:148)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1570)
Suppressed: java.lang.RuntimeException: Asynchronous task failed
at com.google.api.gax.rpc.ServerStreamIterator.hasNext(ServerStreamIterator.java:105)
at SpannerHttpJsonStubMain.main(SpannerHttpJsonStubMain.java:38)
Caused by: com.google.api.gax.httpjson.HttpJsonStatusRuntimeException: Exception in message delivery
at com.google.api.gax.httpjson.HttpJsonClientCallImpl.deliver(HttpJsonClientCallImpl.java:367)
... 8 more
Caused by: com.google.api.gax.httpjson.RestSerializationException: Failed to parse response message
at com.google.api.gax.httpjson.ProtoRestSerializer.fromJson(ProtoRestSerializer.java:107)
at com.google.api.gax.httpjson.ProtoMessageResponseParser.parse(ProtoMessageResponseParser.java:76)
at com.google.api.gax.httpjson.ProtoMessageResponseParser.parse(ProtoMessageResponseParser.java:41)
at com.google.api.gax.httpjson.HttpJsonClientCallImpl.consumeMessageFromStream(HttpJsonClientCallImpl.java:430)
at com.google.api.gax.httpjson.HttpJsonClientCallImpl.deliver(HttpJsonClientCallImpl.java:362)
... 8 more
Caused by: com.google.protobuf.InvalidProtocolBufferException: Cannot invoke "com.google.protobuf.TypeRegistry.getDescriptorForTypeUrl(String)" because "this.registry" is null
at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1309)
at com.google.protobuf.util.JsonFormat$Parser.merge(JsonFormat.java:463)
at com.google.api.gax.httpjson.ProtoRestSerializer.fromJson(ProtoRestSerializer.java:104)
... 12 more
Caused by: java.lang.NullPointerException: Cannot invoke "com.google.protobuf.TypeRegistry.getDescriptorForTypeUrl(String)" because "this.registry" is null
at com.google.protobuf.util.JsonFormat$ParserImpl.mergeAny(JsonFormat.java:1507)
at com.google.protobuf.util.JsonFormat$ParserImpl.access$2000(JsonFormat.java:1276)
at com.google.protobuf.util.JsonFormat$ParserImpl$1.merge(JsonFormat.java:1343)
at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1432)
at com.google.protobuf.util.JsonFormat$ParserImpl.parseFieldValue(JsonFormat.java:1995)
at com.google.protobuf.util.JsonFormat$ParserImpl.mergeRepeatedField(JsonFormat.java:1710)
at com.google.protobuf.util.JsonFormat$ParserImpl.mergeField(JsonFormat.java:1642)
at com.google.protobuf.util.JsonFormat$ParserImpl.mergeMessage(JsonFormat.java:1477)
at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1435)
at com.google.protobuf.util.JsonFormat$ParserImpl.parseFieldValue(JsonFormat.java:1995)
at com.google.protobuf.util.JsonFormat$ParserImpl.mergeField(JsonFormat.java:1646)
at com.google.protobuf.util.JsonFormat$ParserImpl.mergeMessage(JsonFormat.java:1477)
at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1435)
at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1299)
... 14 more
```
Guía de contribución
Evaluación
Este issue todavía no se ha evaluado.