stargate / data-api

JSON document API for Apache Cassandra (formerly known as JSON API)
https://stargate.io
Apache License 2.0
14 stars 16 forks source link

`InsertOperationPage` throws uncaught error for missing `docRowID` for failed insertion #1702

Closed tatu-at-datastax closed 1 week ago

tatu-at-datastax commented 1 week ago

(reported by user via slack https://app.slack.com/client/T054JNCHW/C05PTSGBYL9)

Looks like on row 141 of InsertOperationPage (https://github.com/stargate/data-api/blob/f365a239fc3691015d8ad05eee551500e8b7a66e/src/main/java/io/stargate/sgv2/jsonapi/service/operation/InsertOperationPage.java#L141) there's a problem with:

      results[failedInsertion.position()] =
          new InsertionResult(
              failedInsertion.docRowID().orElseThrow(), InsertionStatus.ERROR, errorIdx);

which leads to generic/vague NoSuchElementException being thrown:

throw new NoSuchElementException("No value present");

this is due docRowID missing; handling is repeated a few times. I am not sure if this is true internal error or not:

It is possible this is due to missing earlier validation (see #1691)?

tatu-at-datastax commented 1 week ago

cc @Yuqi-Du @amorton

amorton commented 1 week ago

what is the production case for this ?

tatu-at-datastax commented 1 week ago

@amorton shared the link on Slack -- there isn't reproduction, just snapshot of stack trace from client side.

amorton commented 1 week ago

image

amorton commented 1 week ago

Call stack

java.util.NoSuchElementException: No value present
    at java.base/java.util.Optional.orElseThrow(Optional.java:377)
    at io.stargate.sgv2.jsonapi.service.operation.InsertOperationPage.perDocumentResult(InsertOperationPage.java:143)
    at io.stargate.sgv2.jsonapi.service.operation.InsertOperationPage.get(InsertOperationPage.java:109)
    at io.stargate.sgv2.jsonapi.service.operation.InsertOperationPage.get(InsertOperationPage.java:28)
    at io.smallrye.context.impl.wrappers.SlowContextualFunction.apply(SlowContextualFunction.java:21)
    at io.smallrye.mutiny.groups.UniOnNotNull.lambda$transform$4(UniOnNotNull.java:116)
    at io.smallrye.context.impl.wrappers.SlowContextualFunction.apply(SlowContextualFunction.java:21)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransform$UniOnItemTransformProcessor.onItem(UniOnItemTransform.java:36)
    at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onItem(UniOperatorProcessor.java:47)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransform$UniOnItemTransformProcessor.onItem(UniOnItemTransform.java:43)
    at io.smallrye.mutiny.operators.uni.builders.UniCreateFromPublisher$PublisherSubscriber.onNext(UniCreateFromPublisher.java:70)
    at io.smallrye.mutiny.subscription.MultiSubscriberAdapter.onItem(MultiSubscriberAdapter.java:27)
    at io.smallrye.mutiny.operators.multi.MultiCollectorOp$CollectorProcessor.onCompletion(MultiCollectorOp.java:99)
    at io.smallrye.mutiny.operators.multi.MultiFlatMapOp$FlatMapMainSubscriber.handleTerminationIfDone(MultiFlatMapOp.java:469)
    at io.smallrye.mutiny.operators.multi.MultiFlatMapOp$FlatMapMainSubscriber.ifDoneOrCancelled(MultiFlatMapOp.java:442)
    at io.smallrye.mutiny.operators.multi.MultiFlatMapOp$FlatMapMainSubscriber.drainLoop(MultiFlatMapOp.java:275)
    at io.smallrye.mutiny.operators.multi.MultiFlatMapOp$FlatMapMainSubscriber.innerComplete(MultiFlatMapOp.java:502)
    at io.smallrye.mutiny.operators.multi.MultiFlatMapOp$FlatMapInner.onCompletion(MultiFlatMapOp.java:573)
    at io.smallrye.mutiny.subscription.MultiSubscriber.onComplete(MultiSubscriber.java:83)
    at io.smallrye.mutiny.converters.uni.UniToMultiPublisher$UniToMultiSubscription.onItem(UniToMultiPublisher.java:96)
    at io.smallrye.mutiny.operators.uni.UniOnItemOrFailureMap$UniOnItemOrFailureMapProcessor.onFailure(UniOnItemOrFailureMap.java:62)
    at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onFailure(UniOperatorProcessor.java:55)
    at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownFailure$KnownFailureSubscription.forward(UniCreateFromKnownFailure.java:38)
    at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownFailure.subscribe(UniCreateFromKnownFailure.java:23)
    at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:81)
    at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:57)
    at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage$CompletionStageUniSubscription.forwardResult(UniCreateFromCompletionStage.java:63)
    at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
    at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
    at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
    at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2179)
    at com.datastax.oss.driver.internal.core.cql.CqlRequestHandler.setFinalResult(CqlRequestHandler.java:324)
    at com.datastax.oss.driver.internal.core.cql.CqlRequestHandler.access$1500(CqlRequestHandler.java:95)
    at com.datastax.oss.driver.internal.core.cql.CqlRequestHandler$NodeResponseCallback.onResponse(CqlRequestHandler.java:655)
    at com.datastax.oss.driver.internal.core.channel.InFlightHandler.channelRead(InFlightHandler.java:257)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
    at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:289)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1407)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:918)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:994)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:1583)
amorton commented 1 week ago

Reproduce with this , the insert is missing the primary key for the table:

{
    "insertMany": {
        "documents": [{
            "name": "aaron",
            "age": 49,
            "country": "New Zealand",
            "human": true
        }],
        "options": {
            "returnDocumentResponses": true
        }
    }
}

rreturn

{
    "errors": [
        {
            "message": "Server failed: root cause: (java.util.NoSuchElementException) No value present",
            "errorCode": "SERVER_UNHANDLED_ERROR",
            "id": "3f3c7c64-8002-4124-bf89-457b3e839896",
            "title": "Server failed",
            "family": "SERVER",
            "scope": "DATABASE"
        }
    ]
}

when working the request with the email address

{
    "insertMany": {
        "documents": [{
            "email" : "aaron.morton@datastax.com",
            "name": "aaron",
            "age": 49,
            "country": "New Zealand",
            "human": true
        }],
        "options": {
            "returnDocumentResponses": true
        }
    }
}

return

{
    "status": {
        "documentResponses": [
            {
                "_id": [
                    "aaron.morton@datastax.com"
                ],
                "status": "OK"
            }
        ],
        "primaryKeySchema": {
            "email": {
                "type": "text"
            }
        }
    }
}