diff --git a/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/validation/ErrorFactories.scala b/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/validation/ErrorFactories.scala index 087cfac8586b..c79f79d24618 100644 --- a/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/validation/ErrorFactories.scala +++ b/ledger/ledger-api-common/src/main/scala/com/digitalasset/platform/server/api/validation/ErrorFactories.scala @@ -130,6 +130,26 @@ class ErrorFactories private (errorCodesVersionSwitcher: ErrorCodesVersionSwitch .asGrpcError, ) + // This error builder covers cases where existing logic handling invalid arguments returned NOT_FOUND. + def invalidArgumentWasNotFound(definiteAnswer: Option[Boolean])(message: String)(implicit + contextualizedErrorLogger: ContextualizedErrorLogger + ): StatusRuntimeException = + errorCodesVersionSwitcher.choose( + v1 = { + val statusBuilder = Status + .newBuilder() + .setCode(Code.NOT_FOUND.value()) + .setMessage(message) + addDefiniteAnswerDetails(definiteAnswer, statusBuilder) + grpcError(statusBuilder.build()) + }, + // TODO error codes: This error group is confusing for this generic error as it can be dispatched + // from call-sites that do not involve command validation (e.g. ApiTransactionService). + v2 = LedgerApiErrors.CommandValidation.InvalidArgument + .Reject(message) + .asGrpcError, + ) + /** @param fieldName An invalid field's name. * @param message A status' message. * @param definiteAnswer A flag that says whether it is a definite answer. Provided only in the context of command deduplication. diff --git a/ledger/ledger-api-common/src/test/suite/scala/com/digitalasset/platform/server/api/validation/ErrorFactoriesSpec.scala b/ledger/ledger-api-common/src/test/suite/scala/com/digitalasset/platform/server/api/validation/ErrorFactoriesSpec.scala index c0c2c2cf05e1..4df56b45ec69 100644 --- a/ledger/ledger-api-common/src/test/suite/scala/com/digitalasset/platform/server/api/validation/ErrorFactoriesSpec.scala +++ b/ledger/ledger-api-common/src/test/suite/scala/com/digitalasset/platform/server/api/validation/ErrorFactoriesSpec.scala @@ -245,6 +245,25 @@ class ErrorFactoriesSpec extends AnyWordSpec with Matchers with TableDrivenPrope } } + "return an invalidArgument (with legacy error code as NOT_FOUND) error" in { + val testCases = Table( + ("definite answer", "expected details"), + (None, Seq.empty), + (Some(false), Seq(definiteAnswers(false))), + ) + + forEvery(testCases) { (definiteAnswer, expectedDetails) => + assertVersionedError(_.invalidArgumentWasNotFound(definiteAnswer)("my message"))( + v1_code = Code.NOT_FOUND, + v1_message = "Invalid argument: my message", + v1_details = expectedDetails, + v2_code = Code.INVALID_ARGUMENT, + v2_message = + s"INVALID_ARGUMENT(8,$correlationId): The submitted command has invalid arguments: my message", + ) + } + } + "should create an ApiException without the stack trace" in { val status = Status.newBuilder().setCode(Code.INTERNAL.value()).build() val exception = grpcError(status) diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/transaction/ApiTransactionService.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/transaction/ApiTransactionService.scala index 1f07d5091e10..8807eca27a55 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/transaction/ApiTransactionService.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/transaction/ApiTransactionService.scala @@ -142,7 +142,7 @@ private[apiserver] final class ApiTransactionService private ( } .getOrElse { Future.failed { - errorFactories.invalidArgument(None)(s"invalid eventId: ${request.eventId}") + errorFactories.invalidArgumentWasNotFound(None)(s"invalid eventId: ${request.eventId}") } } .andThen(logger.logErrorsOnCall[GetTransactionResponse]) @@ -185,7 +185,7 @@ private[apiserver] final class ApiTransactionService private ( } .getOrElse { val msg = s"eventId: ${request.eventId}" - Future.failed(errorFactories.invalidArgument(None)(msg)) + Future.failed(errorFactories.invalidArgumentWasNotFound(None)(msg)) } .andThen(logger.logErrorsOnCall[GetFlatTransactionResponse]) }