diff --git a/src/main/java/io/stargate/sgv2/jsonapi/exception/EmbeddingProviderException.java b/src/main/java/io/stargate/sgv2/jsonapi/exception/EmbeddingProviderException.java index 0148554746..57a9e5a902 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/exception/EmbeddingProviderException.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/exception/EmbeddingProviderException.java @@ -1,5 +1,9 @@ package io.stargate.sgv2.jsonapi.exception; +import java.util.EnumSet; +import java.util.Optional; +import java.util.UUID; + public class EmbeddingProviderException extends ServerException { public static final Scope SCOPE = Scope.EMBEDDING_PROVIDER; @@ -8,10 +12,41 @@ public EmbeddingProviderException(ErrorInstance errorInstance) { super(errorInstance); } + /** + * To construct an EmbeddingProviderException from EGW response. + * + * @see io.stargate.sgv2.jsonapi.service.embedding.gateway.EmbeddingGatewayClient + */ + public EmbeddingProviderException(String code, String title, String body) { + this( + new ErrorInstance( + UUID.randomUUID(), + FAMILY, + SCOPE, + code, + title, + body, + Optional.empty(), + EnumSet.noneOf(ExceptionFlags.class))); + } + public enum Code implements ErrorCode { EMBEDDING_GATEWAY_NOT_AVAILABLE, - CLIENT_ERROR, - SERVER_ERROR; + EMBEDDING_GATEWAY_REQUEST_PROCESSING_ERROR, + EMBEDDING_GATEWAY_RATE_LIMITED, + EMBEDDING_GATEWAY_UNABLE_RESOLVE_AUTHENTICATION_TYPE, + EMBEDDING_GATEWAY_UNEXPECTED_RESPONSE, + + EMBEDDING_REQUEST_ENCODING_ERROR, + EMBEDDING_RESPONSE_DECODING_ERROR, + EMBEDDING_PROVIDER_AUTHENTICATION_KEYS_NOT_PROVIDED, + EMBEDDING_PROVIDER_CLIENT_ERROR, + EMBEDDING_PROVIDER_RATE_LIMITED, + EMBEDDING_PROVIDER_SERVER_ERROR, + EMBEDDING_PROVIDER_TIMEOUT, + EMBEDDING_PROVIDER_UNAVAILABLE, + EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE, + ; private final ErrorTemplate template; diff --git a/src/main/java/io/stargate/sgv2/jsonapi/exception/ErrorCodeV1.java b/src/main/java/io/stargate/sgv2/jsonapi/exception/ErrorCodeV1.java index 9d9642016c..32889e5c40 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/exception/ErrorCodeV1.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/exception/ErrorCodeV1.java @@ -5,18 +5,6 @@ /** ErrorCode is our internal enum that provides codes and a default message for that error code. */ public enum ErrorCodeV1 { /** Embedding provider service error codes. */ - // !!! 16-Dec-2025, tatu: USED BY EMBEDDING-GATEWAY, DO NOT CONVERT "EMBEDDING_" entries yet - EMBEDDING_REQUEST_ENCODING_ERROR("Unable to create embedding provider request message"), - EMBEDDING_RESPONSE_DECODING_ERROR("Unable to parse embedding provider response message"), - EMBEDDING_PROVIDER_AUTHENTICATION_KEYS_NOT_PROVIDED( - "The Embedding Provider authentication keys not provided"), - EMBEDDING_PROVIDER_CLIENT_ERROR("The Embedding Provider returned a HTTP client error"), - EMBEDDING_PROVIDER_SERVER_ERROR("The Embedding Provider returned a HTTP server error"), - EMBEDDING_PROVIDER_RATE_LIMITED("The Embedding Provider rate limited the request"), - EMBEDDING_PROVIDER_TIMEOUT("The Embedding Provider timed out"), - EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE("The Embedding Provider returned an unexpected response"), - EMBEDDING_PROVIDER_API_KEY_MISSING("The Embedding Provider API key is missing"), - VECTOR_SEARCH_NOT_SUPPORTED("Vector search is not enabled for the collection"), VECTOR_SEARCH_INVALID_FUNCTION_NAME("Invalid vector search function name"), @@ -24,18 +12,9 @@ public enum ErrorCodeV1 { VECTOR_SEARCH_TOO_BIG_VALUE("Vector embedding property '$vector' length too big"), VECTORIZE_FEATURE_NOT_AVAILABLE("Vectorize feature is not available in the environment"), - VECTORIZE_SERVICE_NOT_REGISTERED("Vectorize service name provided is not registered : "), - VECTORIZE_SERVICE_TYPE_UNAVAILABLE("Vectorize service unavailable : "), - VECTORIZE_INVALID_AUTHENTICATION_TYPE("Invalid vectorize authentication type"), VECTORIZE_CREDENTIAL_INVALID("Invalid credential name for vectorize"), - - // NOTE: ones used/referenced by `embedding-gateway`, cannot remove: - - INVALID_REQUEST("Request not supported by the data store"), - - EMBEDDING_GATEWAY_ERROR_RATE_LIMIT("Embedding Gateway error rate limit reached for the tenant"), - EMBEDDING_GATEWAY_PROCESSING_ERROR("Embedding Gateway failed to process request"); + ; private final String message; diff --git a/src/main/java/io/stargate/sgv2/jsonapi/exception/JsonApiException.java b/src/main/java/io/stargate/sgv2/jsonapi/exception/JsonApiException.java index d90dc5f65e..acf04c38f3 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/exception/JsonApiException.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/exception/JsonApiException.java @@ -34,9 +34,6 @@ public class JsonApiException extends RuntimeException { { add(VECTOR_SEARCH_NOT_SUPPORTED); add(VECTORIZE_FEATURE_NOT_AVAILABLE); - add(VECTORIZE_SERVICE_NOT_REGISTERED); - add(VECTORIZE_SERVICE_TYPE_UNAVAILABLE); - add(VECTORIZE_INVALID_AUTHENTICATION_TYPE); add(VECTORIZE_CREDENTIAL_INVALID); } }; @@ -50,13 +47,7 @@ public class JsonApiException extends RuntimeException { add(VECTOR_SEARCH_TOO_BIG_VALUE); } }, - ErrorScope.SCHEMA, - new HashSet<>() { - { - add(INVALID_REQUEST); - } - }, - ErrorScope.EMBEDDING); + ErrorScope.SCHEMA); protected JsonApiException(ErrorCodeV1 errorCode) { this(errorCode, errorCode.getMessage(), null); diff --git a/src/main/java/io/stargate/sgv2/jsonapi/exception/mappers/FrameworkExceptionMapper.java b/src/main/java/io/stargate/sgv2/jsonapi/exception/mappers/FrameworkExceptionMapper.java index 0bfad41c47..7f95ee5e92 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/exception/mappers/FrameworkExceptionMapper.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/exception/mappers/FrameworkExceptionMapper.java @@ -20,7 +20,6 @@ import java.util.Collections; import java.util.Map; import java.util.Optional; -import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; import org.jboss.resteasy.reactive.RestResponse; import org.jboss.resteasy.reactive.server.ServerExceptionMapper; @@ -177,11 +176,6 @@ public static RuntimeException translateThrowable(Throwable throwable) { case APIException ae -> ae; case JsonApiException jae -> jae; - // ########## - // WEIRD ONES FROM throwableToErrorMapper - // TODO: AARON - why would this happen ? was in old ThrowableToErrorMapper - case TimeoutException te -> ErrorCodeV1.EMBEDDING_PROVIDER_TIMEOUT.toApiException(); - // ########## // # QUARKUS ERRORS // these are the client 4xx errors , no change means we return them as-is e.g. the 4XX code diff --git a/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/DataVectorizer.java b/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/DataVectorizer.java index f0a5b3213a..8e0c040a53 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/DataVectorizer.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/DataVectorizer.java @@ -2,7 +2,6 @@ import static io.stargate.sgv2.jsonapi.config.constants.DocumentConstants.Fields.VECTOR_EMBEDDING_FIELD; import static io.stargate.sgv2.jsonapi.config.constants.DocumentConstants.Fields.VECTOR_EMBEDDING_TEXT_FIELD; -import static io.stargate.sgv2.jsonapi.exception.ErrorCodeV1.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; @@ -125,11 +124,15 @@ public Uni vectorize(List documents) { // check if we get back the same number of vectors that we asked for if (vectorData.size() != vectorizeTexts.size()) { - throw EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.toApiException( - "Embedding provider '%s' didn't return the expected number of embeddings. Expect: '%d'. Actual: '%d'", - collectionVectorDefinition.vectorizeDefinition().provider(), - vectorizeTexts.size(), - vectorData.size()); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE + .get( + Map.of( + "errorMessage", + "Embedding provider '%s' didn't return the expected number of embeddings. Expect: '%d'. Actual: '%d'" + .formatted( + collectionVectorDefinition.vectorizeDefinition().provider(), + vectorizeTexts.size(), + vectorData.size()))); } for (int vectorPosition = 0; vectorPosition < vectorData.size(); @@ -139,11 +142,17 @@ public Uni vectorize(List documents) { float[] vector = vectorData.get(vectorPosition); // check if all vectors have the expected size if (vector.length != collectionVectorDefinition.vectorSize()) { - throw EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.toApiException( - "Embedding provider '%s' did not return expected embedding length. Expect: '%d'. Actual: '%d'", - collectionVectorDefinition.vectorizeDefinition().provider(), - collectionVectorDefinition.vectorSize(), - vector.length); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE + .get( + Map.of( + "errorMessage", + "Embedding provider '%s' did not return expected embedding length. Expect: '%d'. Actual: '%d'" + .formatted( + collectionVectorDefinition + .vectorizeDefinition() + .provider(), + collectionVectorDefinition.vectorSize(), + vector.length))); } final ArrayNode arrayNode = nodeFactory.arrayNode(vector.length); for (float listValue : vector) { @@ -194,11 +203,14 @@ public Uni vectorize(String vectorizeContent) { float[] vector = vectorData.get(0); // check if vector have the expected size if (vector.length != collectionVectorDefinition.vectorSize()) { - throw EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.toApiException( - "Embedding provider '%s' did not return expected embedding length. Expect: '%d'. Actual: '%d'", - collectionVectorDefinition.vectorizeDefinition().provider(), - collectionVectorDefinition.vectorSize(), - vector.length); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.get( + Map.of( + "errorMessage", + "Embedding provider '%s' did not return expected embedding length. Expect: '%d'. Actual: '%d'" + .formatted( + collectionVectorDefinition.vectorizeDefinition().provider(), + collectionVectorDefinition.vectorSize(), + vector.length))); } return vector; }); @@ -241,11 +253,15 @@ public Uni vectorize(SortClause sortClause) { vectorConfig.getColumnDefinition(VECTOR_EMBEDDING_TEXT_FIELD).orElseThrow(); // check if vector have the expected size if (vector.length != collectionVectorDefinition.vectorSize()) { - throw EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.toApiException( - "Embedding provider '%s' did not return expected embedding length. Expect: '%d'. Actual: '%d'", - collectionVectorDefinition.vectorizeDefinition().provider(), - collectionVectorDefinition.vectorSize(), - vector.length); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE + .get( + Map.of( + "errorMessage", + "Embedding provider '%s' did not return expected embedding length. Expect: '%d'. Actual: '%d'" + .formatted( + collectionVectorDefinition.vectorizeDefinition().provider(), + collectionVectorDefinition.vectorSize(), + vector.length))); } // 12-Jun-2025, tatu: Important! Due to original bad design, we need to allow // replacing of vectorize sort with resolved vector sort: @@ -317,9 +333,11 @@ private Uni> vectorizeTexts( vectorData -> { // Copied from vectorize(List documents) above leaving as is for now if (vectorData.size() != textsToVectorize.size()) { - throw EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.toApiException( - "Embedding provider '%s' didn't return the expected number of embeddings. Expect: '%d'. Actual: '%d'", - providerName, textsToVectorize.size(), vectorData.size()); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.get( + Map.of( + "errorMessage", + "Embedding provider '%s' didn't return the expected number of embeddings. Expect: '%d'. Actual: '%d'" + .formatted(providerName, textsToVectorize.size(), vectorData.size()))); } return vectorData; }); @@ -376,11 +394,14 @@ public void setVector(float[] vector) { private void validateVector(float[] vector) { // Copied from vectorize(List documents) above leaving as is for now - aaron if (vector.length != vectorType.getDimension()) { - throw EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.toApiException( - "Embedding provider '%s' did not return expected embedding length. Expect: '%d'. Actual: '%d'", - vectorType.getVectorizeDefinition().provider(), - vectorType.getDimension(), - vector.length); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.get( + Map.of( + "errorMessage", + "Embedding provider '%s' did not return expected embedding length. Expect: '%d'. Actual: '%d'" + .formatted( + vectorType.getVectorizeDefinition().provider(), + vectorType.getDimension(), + vector.length))); } } diff --git a/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/configuration/EmbeddingProviderResponseValidation.java b/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/configuration/EmbeddingProviderResponseValidation.java index 034a7a3810..5dc02cae86 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/configuration/EmbeddingProviderResponseValidation.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/configuration/EmbeddingProviderResponseValidation.java @@ -1,7 +1,6 @@ package io.stargate.sgv2.jsonapi.service.embedding.configuration; -import static io.stargate.sgv2.jsonapi.exception.ErrorCodeV1.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE; - +import io.stargate.sgv2.jsonapi.exception.EmbeddingProviderException; import io.stargate.sgv2.jsonapi.exception.JsonApiException; import jakarta.ws.rs.client.ClientRequestContext; import jakarta.ws.rs.client.ClientResponseContext; @@ -10,6 +9,7 @@ import jakarta.ws.rs.core.Response; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,8 +53,8 @@ public void filter(ClientRequestContext requestContext, ClientResponseContext re // Throw error if there is no response body if (!responseContext.hasEntity()) { - throw EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.toApiException( - "No response body from the embedding provider"); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.get( + Map.of("errorMessage", "No response body from the embedding provider")); } // response should always be JSON; if not, error out, include raw response message for @@ -72,9 +72,12 @@ public void filter(ClientRequestContext requestContext, ClientResponseContext re logger.error( "Cannot convert the provider's error response to string: " + e.getMessage(), e); } - throw EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.toApiException( - "Expected response Content-Type ('application/json' or 'text/json') from the embedding provider but found '%s'; HTTP Status: %s; The response body is: '%s'.", - contentType, responseContext.getStatus(), responseBody); + + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.get( + Map.of( + "errorMessage", + "Expected response Content-Type ('application/json' or 'text/json') from the embedding provider but found '%s'; HTTP Status: %s; The response body is: '%s'." + .formatted(contentType, responseContext.getStatus(), responseBody))); } } } diff --git a/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/configuration/PropertyBasedServiceConfigStore.java b/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/configuration/PropertyBasedServiceConfigStore.java index 51e99a688f..c84d7d21f3 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/configuration/PropertyBasedServiceConfigStore.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/configuration/PropertyBasedServiceConfigStore.java @@ -1,6 +1,6 @@ package io.stargate.sgv2.jsonapi.service.embedding.configuration; -import io.stargate.sgv2.jsonapi.exception.ErrorCodeV1; +import io.stargate.sgv2.jsonapi.exception.EmbeddingProviderException; import io.stargate.sgv2.jsonapi.service.provider.ModelProvider; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -44,7 +44,9 @@ public ServiceConfigStore.ServiceConfig getConfiguration(ModelProvider modelProv var providerConfig = providersConfig.providers().get(modelProvider.apiName()); if (providerConfig == null || !providerConfig.enabled()) { - throw ErrorCodeV1.VECTORIZE_SERVICE_TYPE_UNAVAILABLE.toApiException(modelProvider.apiName()); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNAVAILABLE.get( + "errorMessage", + "The service provider '%s' is not supported.".formatted(modelProvider.apiName())); } Objects.requireNonNull( diff --git a/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/gateway/EmbeddingGatewayClient.java b/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/gateway/EmbeddingGatewayClient.java index 4baa4625fe..230024a4ca 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/gateway/EmbeddingGatewayClient.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/gateway/EmbeddingGatewayClient.java @@ -7,15 +7,12 @@ import io.stargate.embedding.gateway.EmbeddingService; import io.stargate.sgv2.jsonapi.api.request.EmbeddingCredentials; import io.stargate.sgv2.jsonapi.api.request.tenant.Tenant; -import io.stargate.sgv2.jsonapi.exception.ErrorCodeV1; -import io.stargate.sgv2.jsonapi.exception.JsonApiException; +import io.stargate.sgv2.jsonapi.exception.*; import io.stargate.sgv2.jsonapi.service.embedding.configuration.EmbeddingProvidersConfig; import io.stargate.sgv2.jsonapi.service.embedding.configuration.ServiceConfigStore; import io.stargate.sgv2.jsonapi.service.embedding.operation.EmbeddingProvider; import io.stargate.sgv2.jsonapi.service.provider.ModelProvider; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** Grpc client for embedding gateway service */ public class EmbeddingGatewayClient extends EmbeddingProvider { @@ -172,7 +169,14 @@ else if (value instanceof Boolean) embeddingResponse = grpcGatewayClient.embed(gatewayRequest); } catch (StatusRuntimeException e) { if (e.getStatus().getCode().equals(Status.Code.DEADLINE_EXCEEDED)) { - throw ErrorCodeV1.EMBEDDING_PROVIDER_TIMEOUT.toApiException(e, e.getMessage()); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_TIMEOUT.get( + Map.of( + "provider", + modelProvider().apiName(), + "httpStatus", + String.valueOf(e.getStatus().getCode()), + "errorMessage", + e.getMessage())); } throw e; } @@ -182,9 +186,10 @@ else if (value instanceof Boolean) .transform( gatewayResponse -> { if (gatewayResponse.hasError()) { - throw new JsonApiException( - ErrorCodeV1.valueOf(gatewayResponse.getError().getErrorCode()), - gatewayResponse.getError().getErrorMessage()); + throw new EmbeddingProviderException( + gatewayResponse.getError().getErrorCode(), + gatewayResponse.getError().getErrorTitle(), + gatewayResponse.getError().getErrorBody()); } // aaron - 10 June 2025 - previous code would silently swallow no data returned // but grpc will make sure resp.getEmbeddingsList() is never null diff --git a/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/operation/AwsBedrockEmbeddingProvider.java b/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/operation/AwsBedrockEmbeddingProvider.java index 9277c37cec..82c959563b 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/operation/AwsBedrockEmbeddingProvider.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/operation/AwsBedrockEmbeddingProvider.java @@ -12,7 +12,7 @@ import com.google.common.io.CountingOutputStream; import io.smallrye.mutiny.Uni; import io.stargate.sgv2.jsonapi.api.request.EmbeddingCredentials; -import io.stargate.sgv2.jsonapi.exception.ErrorCodeV1; +import io.stargate.sgv2.jsonapi.exception.EmbeddingProviderException; import io.stargate.sgv2.jsonapi.service.embedding.configuration.EmbeddingProvidersConfig; import io.stargate.sgv2.jsonapi.service.embedding.configuration.ServiceConfigStore; import io.stargate.sgv2.jsonapi.service.provider.ModelInputType; @@ -73,19 +73,33 @@ public Uni vectorize( } if (embeddingCredentials.accessId().isEmpty() && embeddingCredentials.secretId().isEmpty()) { - throw ErrorCodeV1.EMBEDDING_PROVIDER_AUTHENTICATION_KEYS_NOT_PROVIDED.toApiException( - "Both '%s' and '%s' are missing in the header for provider '%s'", - EMBEDDING_AUTHENTICATION_ACCESS_ID_HEADER_NAME, - EMBEDDING_AUTHENTICATION_SECRET_ID_HEADER_NAME, - modelProvider().apiName()); - } else if (embeddingCredentials.accessId().isEmpty()) { - throw ErrorCodeV1.EMBEDDING_PROVIDER_AUTHENTICATION_KEYS_NOT_PROVIDED.toApiException( - "'%s' is missing in the header for provider '%s'", - EMBEDDING_AUTHENTICATION_ACCESS_ID_HEADER_NAME, modelProvider().apiName()); - } else if (embeddingCredentials.secretId().isEmpty()) { - throw ErrorCodeV1.EMBEDDING_PROVIDER_AUTHENTICATION_KEYS_NOT_PROVIDED.toApiException( - "'%s' is missing in the header for provider '%s'", - EMBEDDING_AUTHENTICATION_SECRET_ID_HEADER_NAME, modelProvider().apiName()); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_AUTHENTICATION_KEYS_NOT_PROVIDED.get( + Map.of( + "provider", + modelProvider().apiName(), + "message", + "both '%s' and '%s' headers are missing" + .formatted( + EMBEDDING_AUTHENTICATION_ACCESS_ID_HEADER_NAME, + EMBEDDING_AUTHENTICATION_SECRET_ID_HEADER_NAME))); + } + + if (embeddingCredentials.accessId().isEmpty()) { + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_AUTHENTICATION_KEYS_NOT_PROVIDED.get( + Map.of( + "provider", + modelProvider().apiName(), + "message", + "'%s' header is missing".formatted(EMBEDDING_AUTHENTICATION_ACCESS_ID_HEADER_NAME))); + } + + if (embeddingCredentials.secretId().isEmpty()) { + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_AUTHENTICATION_KEYS_NOT_PROVIDED.get( + Map.of( + "provider", + modelProvider().apiName(), + "message", + "'%s' header is missing".formatted(EMBEDDING_AUTHENTICATION_SECRET_ID_HEADER_NAME))); } var awsCreds = @@ -116,7 +130,14 @@ public Uni vectorize( bytesUsageTracker.requestBytes = inputData.length; requestBuilder.body(SdkBytes.fromByteArray(inputData)).modelId(modelName()); } catch (JsonProcessingException e) { - throw ErrorCodeV1.EMBEDDING_REQUEST_ENCODING_ERROR.toApiException(); + throw EmbeddingProviderException.Code.EMBEDDING_REQUEST_ENCODING_ERROR.get( + Map.of( + "provider", + modelProvider().apiName(), + "model", + modelName(), + "errorMessage", + e.toString())); } }) .thenApply( @@ -150,7 +171,14 @@ public Uni vectorize( batchId, List.of(bedrockResponse.embedding), modelUsage); } catch (IOException e) { - throw ErrorCodeV1.EMBEDDING_RESPONSE_DECODING_ERROR.toApiException(); + throw EmbeddingProviderException.Code.EMBEDDING_RESPONSE_DECODING_ERROR.get( + Map.of( + "provider", + modelProvider().apiName(), + "model", + modelName(), + "errorMessage", + e.toString())); } }); @@ -164,33 +192,56 @@ private Throwable mapBedrockException(BedrockRuntimeException bedrockException) if (bedrockException.statusCode() == Response.Status.REQUEST_TIMEOUT.getStatusCode() || bedrockException.statusCode() == Response.Status.GATEWAY_TIMEOUT.getStatusCode()) { - return ErrorCodeV1.EMBEDDING_PROVIDER_TIMEOUT.toApiException( - "Provider: %s; HTTP Status: %s; Error Message: %s", - modelProvider().apiName(), bedrockException.statusCode(), bedrockException.getMessage()); + return EmbeddingProviderException.Code.EMBEDDING_PROVIDER_TIMEOUT.get( + Map.of( + "provider", + modelProvider().apiName(), + "httpStatus", + String.valueOf(bedrockException.statusCode()), + "errorMessage", + bedrockException.getMessage())); } if (bedrockException.statusCode() == Response.Status.TOO_MANY_REQUESTS.getStatusCode()) { - return ErrorCodeV1.EMBEDDING_PROVIDER_RATE_LIMITED.toApiException( - "Provider: %s; HTTP Status: %s; Error Message: %s", - modelProvider().apiName(), bedrockException.statusCode(), bedrockException.getMessage()); + return EmbeddingProviderException.Code.EMBEDDING_PROVIDER_RATE_LIMITED.get( + Map.of( + "provider", + modelProvider().apiName(), + "httpStatus", + String.valueOf(bedrockException.statusCode()), + "errorMessage", + bedrockException.getMessage())); } if (bedrockException.statusCode() > 400 && bedrockException.statusCode() < 500) { - return ErrorCodeV1.EMBEDDING_PROVIDER_CLIENT_ERROR.toApiException( - "Provider: %s; HTTP Status: %s; Error Message: %s", - modelProvider().apiName(), bedrockException.statusCode(), bedrockException.getMessage()); + return EmbeddingProviderException.Code.EMBEDDING_PROVIDER_CLIENT_ERROR.get( + "provider", + modelProvider().apiName(), + "httpStatus", + String.valueOf(bedrockException.statusCode()), + "errorMessage", + bedrockException.getMessage()); } if (bedrockException.statusCode() >= 500) { - return ErrorCodeV1.EMBEDDING_PROVIDER_SERVER_ERROR.toApiException( - "Provider: %s; HTTP Status: %s; Error Message: %s", - modelProvider().apiName(), bedrockException.statusCode(), bedrockException.getMessage()); + return EmbeddingProviderException.Code.EMBEDDING_PROVIDER_SERVER_ERROR.get( + "provider", + modelProvider().apiName(), + "httpStatus", + String.valueOf(bedrockException.statusCode()), + "errorMessage", + bedrockException.getMessage()); } // All other errors, Should never happen as all errors are covered above - return ErrorCodeV1.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.toApiException( - "Provider: %s; HTTP Status: %s; Error Message: %s", - modelProvider().apiName(), bedrockException.statusCode(), bedrockException.getMessage()); + return EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.get( + Map.of( + "errorMessage", + "Provider: %s; HTTP Status: %s; Error Message: %s" + .formatted( + modelProvider().apiName(), + bedrockException.statusCode(), + bedrockException.getMessage()))); } private static class ByteUsageTracker { diff --git a/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingProvider.java b/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingProvider.java index a4c2543927..77810f6276 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingProvider.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingProvider.java @@ -1,14 +1,11 @@ package io.stargate.sgv2.jsonapi.service.embedding.operation; import static io.stargate.sgv2.jsonapi.config.constants.HttpConstants.EMBEDDING_AUTHENTICATION_TOKEN_HEADER_NAME; -import static io.stargate.sgv2.jsonapi.exception.ErrorCodeV1.EMBEDDING_PROVIDER_API_KEY_MISSING; import static jakarta.ws.rs.core.Response.Status.Family.CLIENT_ERROR; import io.smallrye.mutiny.Uni; import io.stargate.sgv2.jsonapi.api.request.EmbeddingCredentials; -import io.stargate.sgv2.jsonapi.exception.ErrorCodeV1; -import io.stargate.sgv2.jsonapi.exception.JsonApiException; -import io.stargate.sgv2.jsonapi.exception.ServerException; +import io.stargate.sgv2.jsonapi.exception.*; import io.stargate.sgv2.jsonapi.service.embedding.configuration.EmbeddingProvidersConfig; import io.stargate.sgv2.jsonapi.service.embedding.configuration.ServiceConfigStore; import io.stargate.sgv2.jsonapi.service.provider.*; @@ -177,9 +174,12 @@ protected String replaceParameters(String template, Map paramete protected void checkEmbeddingApiKeyHeader(Optional apiKey) { if (apiKey.isEmpty()) { - throw EMBEDDING_PROVIDER_API_KEY_MISSING.toApiException( - "header value `%s` is missing for embedding provider: %s", - EMBEDDING_AUTHENTICATION_TOKEN_HEADER_NAME, modelProvider().apiName()); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_AUTHENTICATION_KEYS_NOT_PROVIDED.get( + Map.of( + "provider", + modelProvider().apiName(), + "message", + "'%s' header is missing".formatted(EMBEDDING_AUTHENTICATION_TOKEN_HEADER_NAME))); } } @@ -207,8 +207,9 @@ protected int atMostRetries() { protected boolean decideRetry(Throwable throwable) { var retry = - (throwable.getCause() instanceof JsonApiException jae - && jae.getErrorCode() == ErrorCodeV1.EMBEDDING_PROVIDER_TIMEOUT); + (throwable.getCause() instanceof APIException apiException + && apiException.code.equals( + EmbeddingProviderException.Code.EMBEDDING_PROVIDER_TIMEOUT.name())); return retry || super.decideRetry(throwable); } @@ -219,45 +220,65 @@ protected RuntimeException mapHTTPError(Response jakartaResponse, String errorMe if (jakartaResponse.getStatus() == Response.Status.REQUEST_TIMEOUT.getStatusCode() || jakartaResponse.getStatus() == Response.Status.GATEWAY_TIMEOUT.getStatusCode()) { - return ErrorCodeV1.EMBEDDING_PROVIDER_TIMEOUT.toApiException( - "Provider: %s; HTTP Status: %s; Error Message: %s", - modelProvider().apiName(), jakartaResponse.getStatus(), errorMessage); + return EmbeddingProviderException.Code.EMBEDDING_PROVIDER_TIMEOUT.get( + Map.of( + "provider", + modelProvider().apiName(), + "httpStatus", + String.valueOf(jakartaResponse.getStatus()), + "errorMessage", + errorMessage)); } // Status code == 429 if (jakartaResponse.getStatus() == Response.Status.TOO_MANY_REQUESTS.getStatusCode()) { - return ErrorCodeV1.EMBEDDING_PROVIDER_RATE_LIMITED.toApiException( - "Provider: %s; HTTP Status: %s; Error Message: %s", - modelProvider().apiName(), jakartaResponse.getStatus(), errorMessage); + return EmbeddingProviderException.Code.EMBEDDING_PROVIDER_RATE_LIMITED.get( + Map.of( + "provider", + modelProvider().apiName(), + "httpStatus", + String.valueOf(jakartaResponse.getStatus()), + "errorMessage", + errorMessage)); } // Status code in 4XX other than 429 if (jakartaResponse.getStatusInfo().getFamily() == CLIENT_ERROR) { - return ErrorCodeV1.EMBEDDING_PROVIDER_CLIENT_ERROR.toApiException( - "Provider: %s; HTTP Status: %s; Error Message: %s", - modelProvider().apiName(), jakartaResponse.getStatus(), errorMessage); + return EmbeddingProviderException.Code.EMBEDDING_PROVIDER_CLIENT_ERROR.get( + "provider", + modelProvider().apiName(), + "httpStatus", + String.valueOf(jakartaResponse.getStatus()), + "errorMessage", + errorMessage); } // Status code in 5XX if (jakartaResponse.getStatusInfo().getFamily() == Response.Status.Family.SERVER_ERROR) { - return ErrorCodeV1.EMBEDDING_PROVIDER_SERVER_ERROR.toApiException( - "Provider: %s; HTTP Status: %s; Error Message: %s", - modelProvider().apiName(), jakartaResponse.getStatus(), errorMessage); + return EmbeddingProviderException.Code.EMBEDDING_PROVIDER_SERVER_ERROR.get( + "provider", + modelProvider().apiName(), + "httpStatus", + String.valueOf(jakartaResponse.getStatus()), + "errorMessage", + errorMessage); } // All other errors, Should never happen as all errors are covered above - return ErrorCodeV1.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.toApiException( - "Provider: %s; HTTP Status: %s; Error Message: %s", - modelProvider().apiName(), jakartaResponse.getStatus(), errorMessage); + return EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.get( + Map.of( + "errorMessage", + "Provider: %s; HTTP Status: %s; Error Message: %s" + .formatted(modelProvider().apiName(), jakartaResponse.getStatus(), errorMessage))); } /** Call this from the subclass when the response from the provider is empty */ protected void throwEmptyData(Response jakartaResponse) { - throw ErrorCodeV1.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.toApiException( - "Provider: %s; HTTP Status: %s; Error Message: %s", - modelProvider().apiName(), - jakartaResponse.getStatus(), - "ModelProvider returned empty data for model %s".formatted(modelName())); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.get( + Map.of( + "errorMessage", + "Provider: %s; HTTP Status: %s; Error Message: The embedding provider returned empty data for model %s" + .formatted(modelProvider().apiName(), jakartaResponse.getStatus(), modelName()))); } /** diff --git a/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingProviderFactory.java b/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingProviderFactory.java index 7e1c0ceb5c..0f44f69061 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingProviderFactory.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingProviderFactory.java @@ -4,7 +4,7 @@ import io.stargate.embedding.gateway.EmbeddingService; import io.stargate.sgv2.jsonapi.api.request.tenant.Tenant; import io.stargate.sgv2.jsonapi.config.OperationsConfig; -import io.stargate.sgv2.jsonapi.exception.ErrorCodeV1; +import io.stargate.sgv2.jsonapi.exception.EmbeddingProviderException; import io.stargate.sgv2.jsonapi.service.embedding.configuration.EmbeddingProvidersConfig; import io.stargate.sgv2.jsonapi.service.embedding.configuration.ServiceConfigStore; import io.stargate.sgv2.jsonapi.service.embedding.gateway.EmbeddingGatewayClient; @@ -84,8 +84,9 @@ public EmbeddingProvider create( ModelProvider.fromApiName(serviceName) .orElseThrow( () -> - ErrorCodeV1.VECTORIZE_SERVICE_TYPE_UNAVAILABLE.toApiException( - "unknown service provider '%s'", serviceName)); + EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNAVAILABLE.get( + "errorMessage", + "The service provider '%s' is not supported.".formatted(serviceName))); return create( tenant, @@ -134,24 +135,26 @@ public EmbeddingProvider create( // checking this and existing because the rest of the function is validating models etc exist. Optional> clazz = serviceConfig.implementationClass(); if (clazz.isEmpty()) { - throw ErrorCodeV1.VECTORIZE_SERVICE_TYPE_UNAVAILABLE.toApiException( - "custom class undefined"); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNAVAILABLE.get( + "errorMessage", "custom class undefined"); } try { return (EmbeddingProvider) clazz.get().getConstructor(int.class).newInstance(dimension); } catch (Exception e) { - throw ErrorCodeV1.VECTORIZE_SERVICE_TYPE_UNAVAILABLE.toApiException( - "custom class provided ('%s') does not resolve to EmbeddingProvider", - clazz.get().getCanonicalName()); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNAVAILABLE.get( + "errorMessage", + "custom class provided ('%s') does not resolve to EmbeddingProvider" + .formatted(clazz.get().getCanonicalName())); } } EmbeddingProvidersConfig.EmbeddingProviderConfig providerConfig = embeddingProvidersConfig.providers().get(serviceConfig.modelProvider().apiName()); if (providerConfig == null) { - throw ErrorCodeV1.VECTORIZE_SERVICE_TYPE_UNAVAILABLE.toApiException( - "unknown service provider '%s'", serviceConfig.modelProvider()); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNAVAILABLE.get( + "errorMessage", + "The service provider '%s' is not supported.".formatted(serviceConfig.modelProvider())); } EmbeddingProvidersConfig.EmbeddingProviderConfig.ModelConfig modelConfig = @@ -160,9 +163,10 @@ public EmbeddingProvider create( .findFirst() .orElseThrow( () -> - ErrorCodeV1.VECTORIZE_SERVICE_TYPE_UNAVAILABLE.toApiException( - "unknown model '%s' for service provider '%s'", - modelName, serviceConfig.modelProvider())); + EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNAVAILABLE.get( + "errorMessage", + "The model '%s' for service provider '%s' is not supported." + .formatted(modelName, serviceConfig.modelProvider()))); if (operationsConfig.enableEmbeddingGateway()) { return new EmbeddingGatewayClient( diff --git a/src/main/java/io/stargate/sgv2/jsonapi/service/operation/embeddings/EmbeddingDeferredAction.java b/src/main/java/io/stargate/sgv2/jsonapi/service/operation/embeddings/EmbeddingDeferredAction.java index b074dbe9b8..e064d32074 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/service/operation/embeddings/EmbeddingDeferredAction.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/service/operation/embeddings/EmbeddingDeferredAction.java @@ -1,12 +1,12 @@ package io.stargate.sgv2.jsonapi.service.operation.embeddings; -import static io.stargate.sgv2.jsonapi.exception.ErrorCodeV1.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE; - +import io.stargate.sgv2.jsonapi.exception.EmbeddingProviderException; import io.stargate.sgv2.jsonapi.service.cqldriver.executor.VectorizeDefinition; import io.stargate.sgv2.jsonapi.service.schema.tables.ApiVectorType; import io.stargate.sgv2.jsonapi.service.shredding.DeferredAction; import io.stargate.sgv2.jsonapi.util.recordable.PrettyPrintable; import io.stargate.sgv2.jsonapi.util.recordable.Recordable; +import java.util.Map; import java.util.Objects; import java.util.function.Consumer; @@ -94,9 +94,11 @@ private void setFailure(RuntimeException failure) { private void validateVector(float[] vector) { if (vector.length != dimension) { - throw EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.toApiException( - "Embedding provider '%s' did not return expected embedding length. Expect: '%d'. Actual: '%d'", - vectorizeDefinition.provider(), dimension, vector.length); + throw EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.get( + Map.of( + "errorMessage", + "Embedding provider '%s' did not return expected embedding length. Expect: '%d'. Actual: '%d'" + .formatted(vectorizeDefinition.provider(), dimension, vector.length))); } } diff --git a/src/main/java/io/stargate/sgv2/jsonapi/service/reranking/gateway/RerankingEGWClient.java b/src/main/java/io/stargate/sgv2/jsonapi/service/reranking/gateway/RerankingEGWClient.java index b91f7358be..15dc39deba 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/service/reranking/gateway/RerankingEGWClient.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/service/reranking/gateway/RerankingEGWClient.java @@ -99,7 +99,7 @@ public Uni rerank( // 22-Jan-2026, tatu: This is ugly. But has to be done to work around fragility // of exception mapping throw SchemaException.Code.valueOf(gatewayResponse.getError().getErrorCode()) - .withPreformattedMessage(gatewayResponse.getError().getErrorMessage()); + .withPreformattedMessage(gatewayResponse.getError().getErrorBody()); } return new BatchedRerankingResponse( diff --git a/src/main/java/io/stargate/sgv2/jsonapi/service/resolver/ValidateCredentials.java b/src/main/java/io/stargate/sgv2/jsonapi/service/resolver/ValidateCredentials.java index f846388f9e..c076be0b41 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/service/resolver/ValidateCredentials.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/service/resolver/ValidateCredentials.java @@ -40,7 +40,7 @@ public boolean validate(String provider, String value) { embeddingService.validateCredential(validateCredentialRequest.build()); if (validateCredentialResponse.hasError()) { throw ErrorCodeV1.VECTORIZE_CREDENTIAL_INVALID.toApiException( - " with error: %s", validateCredentialResponse.getError().getErrorMessage()); + " with error: %s", validateCredentialResponse.getError().getErrorBody()); } return validateCredentialResponse.getValidity(); } diff --git a/src/main/proto/embedding_gateway.proto b/src/main/proto/embedding_gateway.proto index e7e2114d3c..51ab52a4b6 100644 --- a/src/main/proto/embedding_gateway.proto +++ b/src/main/proto/embedding_gateway.proto @@ -68,7 +68,8 @@ message EmbeddingResponse { // The error response message for the embedding gateway gRPC API message ErrorResponse { string error_code = 1; - string error_message = 2; + string error_title = 2; + string error_body = 3; } } @@ -162,7 +163,8 @@ message GetSupportedProvidersResponse { // The error response message for the embedding gateway gRPC API message ErrorResponse { string error_code = 1; - string error_message = 2; + string error_title = 2; + string error_body = 3; } } @@ -181,7 +183,8 @@ message ValidateCredentialResponse { message Error { string error_code = 1; - string error_message = 2; + string error_title = 2; + string error_body = 3; } } @@ -231,7 +234,8 @@ message RerankingResponse { message ErrorResponse { string error_code = 1; - string error_message = 2; + string error_title = 2; + string error_body = 3; } } @@ -283,7 +287,8 @@ message GetSupportedRerankingProvidersResponse { message ErrorResponse { string error_code = 1; - string error_message = 2; + string error_title = 2; + string error_body = 3; } } diff --git a/src/main/resources/errors.yaml b/src/main/resources/errors.yaml index a8b6b77076..525de57707 100644 --- a/src/main/resources/errors.yaml +++ b/src/main/resources/errors.yaml @@ -2621,13 +2621,87 @@ server-errors: Underlying problem: ${errorMessage}. - scope: EMBEDDING_PROVIDER - code: CLIENT_ERROR - title: The Embedding Provider returned a HTTP client error + code: EMBEDDING_GATEWAY_REQUEST_PROCESSING_ERROR + title: Embedding Gateway failed to process request + body: |- + Embedding Gateway failed to process request + Underlying problem: ${errorMessage}. + + - scope: EMBEDDING_PROVIDER + code: EMBEDDING_GATEWAY_RATE_LIMITED + title: Embedding Gateway rate limited the request + body: |- + Embedding Gateway rate limited the request + Underlying problem: ${errorMessage}. + + - scope: EMBEDDING_PROVIDER + code: EMBEDDING_GATEWAY_UNABLE_RESOLVE_AUTHENTICATION_TYPE + title: Embedding Gateway unable to resolve authentication type + body: |- + Embedding Gateway unable to resolve authentication type. + Underlying problem: ${errorMessage}. + + - scope: EMBEDDING_PROVIDER + code: EMBEDDING_GATEWAY_UNEXPECTED_RESPONSE + title: Embedding Gateway returned an unexpected response. + body: |- + Embedding Gateway returned an unexpected response. + Underlying problem: ${errorMessage}. + + - scope: EMBEDDING_PROVIDER + code: EMBEDDING_REQUEST_ENCODING_ERROR + title: Embedding request encoding failure + body: |- + Internal error: failed to encode embedding request (provider '${provider}', model '${model}'). + Underlying problem: ${errorMessage} + + - scope: EMBEDDING_PROVIDER + code: EMBEDDING_RESPONSE_DECODING_ERROR + title: Embedding request response decoding failure + body: |- + Internal error: failed to decode response to embedding request (provider '${provider}', model '${model}'). + Underlying problem: ${errorMessage} + + - scope: EMBEDDING_PROVIDER + code: EMBEDDING_PROVIDER_AUTHENTICATION_KEYS_NOT_PROVIDED + title: Authentication header(s) missing from embedding request body: |- - Provider: ${provider}; HTTP Status: ${httpStatus}; Error Message: ${errorMessage} + Missing authentication header(s) from embedding request (provider '${provider}'): ${message}'). - scope: EMBEDDING_PROVIDER - code: SERVER_ERROR + code: EMBEDDING_PROVIDER_CLIENT_ERROR title: The Embedding Provider returned a HTTP client error body: |- - Provider: ${provider}; HTTP Status: ${httpStatus}; Error Message: ${errorMessage} \ No newline at end of file + Provider '${provider}' returned a HTTP client error with HTTP ${httpStatus}; error message: ${errorMessage} + + - scope: EMBEDDING_PROVIDER + code: EMBEDDING_PROVIDER_RATE_LIMITED + title: Embedding provider rate limited the request + body: |- + Provider '${provider}' rate limited the request with HTTP ${httpStatus}; error message: ${errorMessage} + + - scope: EMBEDDING_PROVIDER + code: EMBEDDING_PROVIDER_SERVER_ERROR + title: The Embedding Provider returned a HTTP server error + body: |- + Provider '${provider}' returned a HTTP server error with HTTP ${httpStatus}; error message: ${errorMessage} + + - scope: EMBEDDING_PROVIDER + code: EMBEDDING_PROVIDER_TIMEOUT + title: The Embedding Provider request timed out + body: |- + Provider '${provider}' request timed out with HTTP ${httpStatus}; error message: ${errorMessage} + + - scope: EMBEDDING_PROVIDER + code: EMBEDDING_PROVIDER_UNAVAILABLE + title: The Embedding Provider is unavailable + body: |- + The Embedding Provider is unavailable + Underlying problem: ${errorMessage} + + - scope: EMBEDDING_PROVIDER + code: EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE + title: The Embedding Provider returned an unexpected response + body: |- + The Embedding Provider returned an unexpected response. + Underlying problem: ${errorMessage}. \ No newline at end of file diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/VectorizeSearchIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/VectorizeSearchIntegrationTest.java index d220e04480..321deab2e8 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/VectorizeSearchIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/VectorizeSearchIntegrationTest.java @@ -9,6 +9,7 @@ import io.quarkus.test.common.WithTestResource; import io.quarkus.test.junit.QuarkusIntegrationTest; import io.stargate.sgv2.jsonapi.exception.DocumentException; +import io.stargate.sgv2.jsonapi.exception.EmbeddingProviderException; import io.stargate.sgv2.jsonapi.exception.SortException; import io.stargate.sgv2.jsonapi.testresource.DseTestResource; import java.util.Arrays; @@ -1159,10 +1160,12 @@ public void findOneAndUpdate_sortClause() { .statusCode(200) .body("$", responseIsError()) .body("errors", hasSize(1)) - .body("errors[0].errorCode", is("VECTORIZE_SERVICE_TYPE_UNAVAILABLE")) + .body( + "errors[0].errorCode", + is(EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNAVAILABLE.name())) .body( "errors[0].message", - containsString("unknown model 'random' for service provider 'nvidia'")); + containsString("The model 'random' for service provider 'nvidia' is not supported")); } } diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/tables/InsertOneTableIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/tables/InsertOneTableIntegrationTest.java index 5486b4d730..6e34f4d7c8 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/tables/InsertOneTableIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/tables/InsertOneTableIntegrationTest.java @@ -8,7 +8,7 @@ import io.quarkus.test.common.WithTestResource; import io.quarkus.test.junit.QuarkusIntegrationTest; import io.stargate.sgv2.jsonapi.exception.DocumentException; -import io.stargate.sgv2.jsonapi.exception.ErrorCodeV1; +import io.stargate.sgv2.jsonapi.exception.EmbeddingProviderException; import io.stargate.sgv2.jsonapi.service.operation.filters.table.codecs.JSONCodecRegistryTestData; import io.stargate.sgv2.jsonapi.testresource.DseTestResource; import io.stargate.sgv2.jsonapi.util.Base64Util; @@ -1734,8 +1734,9 @@ void insertDifferentVectorizeDimensions() { } """) .hasSingleApiError( - ErrorCodeV1.EMBEDDING_PROVIDER_CLIENT_ERROR.name(), - "The Embedding Provider returned a HTTP client error: Provider: openai; HTTP Status: 401; Error Message: \"Incorrect API key provided: test_emb"); + EmbeddingProviderException.Code.EMBEDDING_PROVIDER_CLIENT_ERROR, + EmbeddingProviderException.class, + "Provider 'openai' returned a HTTP client error with HTTP 401; error message: \"Incorrect API key provided: test_emb"); } @Order(2) @@ -1782,8 +1783,9 @@ void insertDifferentVectorizeModels() { } """) .hasSingleApiError( - ErrorCodeV1.EMBEDDING_PROVIDER_CLIENT_ERROR.name(), - "The Embedding Provider returned a HTTP client error: Provider: openai; HTTP Status: 401; Error Message: \"Incorrect API key provided: test_emb"); + EmbeddingProviderException.Code.EMBEDDING_PROVIDER_CLIENT_ERROR, + EmbeddingProviderException.class, + "Provider 'openai' returned a HTTP client error with HTTP 401; error message: \"Incorrect API key provided: test_emb"); } @Order(3) @@ -1829,10 +1831,13 @@ void insertDifferentVectorizeProviders() { } """) .hasSingleApiError( - ErrorCodeV1.EMBEDDING_PROVIDER_CLIENT_ERROR, + EmbeddingProviderException.Code.EMBEDDING_PROVIDER_CLIENT_ERROR, + EmbeddingProviderException.class, anyOf( - containsString("Provider: openai; HTTP Status: 401; Error Message: "), - containsString("Provider: jinaAI; HTTP Status: 401; Error Message: "))); + containsString( + "Provider 'openai' returned a HTTP client error with HTTP 401; error message:"), + containsString( + "Provider 'jinaAI' returned a HTTP client error with HTTP 401; error message:"))); } } } diff --git a/src/test/java/io/stargate/sgv2/jsonapi/exception/JsonApiExceptionTest.java b/src/test/java/io/stargate/sgv2/jsonapi/exception/JsonApiExceptionTest.java index e5e3152f33..f3da0b5aca 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/exception/JsonApiExceptionTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/exception/JsonApiExceptionTest.java @@ -1,11 +1,7 @@ package io.stargate.sgv2.jsonapi.exception; -import static org.assertj.core.api.Assertions.assertThat; - import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.TestProfile; -import io.stargate.sgv2.jsonapi.api.model.command.CommandResult; -import io.stargate.sgv2.jsonapi.api.model.command.tracing.RequestTracing; import io.stargate.sgv2.jsonapi.testresource.NoGlobalResourcesTestProfile; import org.junit.jupiter.api.Test; @@ -16,19 +12,20 @@ class JsonApiExceptionTest { @Test public void happyPath() { - var commandResult = - CommandResult.statusOnlyBuilder(RequestTracing.NO_OP) - .addThrowable(new JsonApiException(ErrorCodeV1.INVALID_REQUEST)) - .build(); - - assertThat(commandResult.data()).isNull(); - assertThat(commandResult.status()).isEmpty(); - assertThat(commandResult.errors()) - .singleElement() - .satisfies( - error -> { - assertThat(error.message()).isEqualTo("Request not supported by the data store"); - assertThat(error.errorCode()).isEqualTo(ErrorCodeV1.INVALID_REQUEST.name()); - }); + // var commandResult = + // CommandResult.statusOnlyBuilder(RequestTracing.NO_OP) + // .addThrowable(new JsonApiException(ErrorCodeV1.INVALID_REQUEST)) + // .build(); + // + // assertThat(commandResult.data()).isNull(); + // assertThat(commandResult.status()).isEmpty(); + // assertThat(commandResult.errors()) + // .singleElement() + // .satisfies( + // error -> { + // assertThat(error.message()).isEqualTo("Request not supported by the data + // store"); + // assertThat(error.errorCode()).isEqualTo(ErrorCodeV1.INVALID_REQUEST.name()); + // }); } } diff --git a/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/DataVectorizerTest.java b/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/DataVectorizerTest.java index 1748773898..7b2b22dfb0 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/DataVectorizerTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/DataVectorizerTest.java @@ -15,10 +15,7 @@ import io.stargate.sgv2.jsonapi.api.model.command.clause.sort.SortExpression; import io.stargate.sgv2.jsonapi.api.request.EmbeddingCredentials; import io.stargate.sgv2.jsonapi.config.constants.DocumentConstants; -import io.stargate.sgv2.jsonapi.exception.DocumentException; -import io.stargate.sgv2.jsonapi.exception.ErrorCodeV1; -import io.stargate.sgv2.jsonapi.exception.JsonApiException; -import io.stargate.sgv2.jsonapi.exception.SchemaException; +import io.stargate.sgv2.jsonapi.exception.*; import io.stargate.sgv2.jsonapi.service.cqldriver.executor.VectorColumnDefinition; import io.stargate.sgv2.jsonapi.service.cqldriver.executor.VectorConfig; import io.stargate.sgv2.jsonapi.service.cqldriver.executor.VectorizeDefinition; @@ -247,12 +244,10 @@ public Uni vectorize( .awaitFailure() .getFailure(); assertThat(failure) - .isInstanceOf(JsonApiException.class) .hasFieldOrPropertyWithValue( - "errorCode", ErrorCodeV1.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE) - .hasFieldOrPropertyWithValue( - "message", - "The Embedding Provider returned an unexpected response: Embedding provider 'custom' didn't return the expected number of embeddings. Expect: '2'. Actual: '3'"); + "code", EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.name()) + .hasMessageContaining( + "Embedding provider 'custom' didn't return the expected number of embeddings. Expect: '2'. Actual: '3'"); } @Test @@ -291,12 +286,10 @@ public void testWithUnmatchedVectorSize() { .awaitFailure() .getFailure(); assertThat(failure) - .isInstanceOf(JsonApiException.class) - .hasFieldOrPropertyWithValue( - "errorCode", ErrorCodeV1.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE) .hasFieldOrPropertyWithValue( - "message", - "The Embedding Provider returned an unexpected response: Embedding provider 'custom' did not return expected embedding length. Expect: '4'. Actual: '3'"); + "code", EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.name()) + .hasMessageContaining( + "Embedding provider 'custom' did not return expected embedding length. Expect: '4'. Actual: '3'"); } } diff --git a/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingGatewayClientTest.java b/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingGatewayClientTest.java index 339702402c..3875224e93 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingGatewayClientTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingGatewayClientTest.java @@ -13,8 +13,8 @@ import io.stargate.embedding.gateway.EmbeddingService; import io.stargate.sgv2.jsonapi.TestConstants; import io.stargate.sgv2.jsonapi.api.request.EmbeddingCredentials; -import io.stargate.sgv2.jsonapi.exception.ErrorCodeV1; -import io.stargate.sgv2.jsonapi.exception.JsonApiException; +import io.stargate.sgv2.jsonapi.exception.APIException; +import io.stargate.sgv2.jsonapi.exception.EmbeddingProviderException; import io.stargate.sgv2.jsonapi.service.embedding.configuration.EmbeddingProvidersConfig; import io.stargate.sgv2.jsonapi.service.embedding.configuration.EmbeddingProvidersConfigImpl; import io.stargate.sgv2.jsonapi.service.embedding.configuration.ServiceConfigStore; @@ -197,13 +197,15 @@ void handleError() { EmbeddingGateway.EmbeddingResponse.newBuilder(); EmbeddingGateway.EmbeddingResponse.ErrorResponse.Builder errorResponseBuilder = EmbeddingGateway.EmbeddingResponse.ErrorResponse.newBuilder(); - JsonApiException apiException = - ErrorCodeV1.EMBEDDING_PROVIDER_RATE_LIMITED.toApiException( - "Error Code : %s response description : %s", 429, "Too Many Requests"); + APIException apiException = + EmbeddingProviderException.Code.EMBEDDING_PROVIDER_RATE_LIMITED.get( + Map.of( + "provider", "TEST-MODEL", "httpStatus", "429", "errorMessage", "Slow Down Dude!")); errorResponseBuilder - .setErrorCode(apiException.getErrorCode().name()) - .setErrorMessage(apiException.getMessage()); + .setErrorCode(apiException.code) + .setErrorTitle(apiException.title) + .setErrorBody(apiException.body); builder.setError(errorResponseBuilder.build()); when(embeddingService.embed(any())).thenReturn(Uni.createFrom().item(builder.build())); @@ -234,12 +236,12 @@ void handleError() { .getFailure(); assertThat(result) - .isInstanceOf(JsonApiException.class) + .isInstanceOf(APIException.class) .satisfies( e -> { - JsonApiException exception = (JsonApiException) e; + APIException exception = (APIException) e; assertThat(exception.getMessage()).isEqualTo(apiException.getMessage()); - assertThat(exception.getErrorCode()).isEqualTo(apiException.getErrorCode()); + assertThat(exception.code).isEqualTo(apiException.code); }); } } diff --git a/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingProviderErrorMessageTest.java b/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingProviderErrorMessageTest.java index 81f0538a3d..a07b2ba825 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingProviderErrorMessageTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/EmbeddingProviderErrorMessageTest.java @@ -7,8 +7,8 @@ import io.smallrye.mutiny.helpers.test.UniAssertSubscriber; import io.stargate.sgv2.jsonapi.TestConstants; import io.stargate.sgv2.jsonapi.api.request.EmbeddingCredentials; -import io.stargate.sgv2.jsonapi.exception.ErrorCodeV1; -import io.stargate.sgv2.jsonapi.exception.JsonApiException; +import io.stargate.sgv2.jsonapi.exception.APIException; +import io.stargate.sgv2.jsonapi.exception.EmbeddingProviderException; import io.stargate.sgv2.jsonapi.service.embedding.configuration.EmbeddingProvidersConfig; import io.stargate.sgv2.jsonapi.service.embedding.configuration.EmbeddingProvidersConfigImpl; import io.stargate.sgv2.jsonapi.service.embedding.configuration.ServiceConfigStore; @@ -110,11 +110,12 @@ public void test429() throws Exception { var exception = vectorizeWithError("429"); assertThat(exception) - .isInstanceOf(JsonApiException.class) - .hasFieldOrPropertyWithValue("errorCode", ErrorCodeV1.EMBEDDING_PROVIDER_RATE_LIMITED) + .isInstanceOf(APIException.class) + .hasFieldOrPropertyWithValue( + "code", EmbeddingProviderException.Code.EMBEDDING_PROVIDER_RATE_LIMITED.name()) .hasFieldOrPropertyWithValue( "message", - "The Embedding Provider rate limited the request: Provider: nvidia; HTTP Status: 429; Error Message: {\"object\":\"list\"}"); + "Provider 'nvidia' rate limited the request with HTTP 429; error message: {\"object\":\"list\"}"); } @Test @@ -123,11 +124,11 @@ public void test4xx() throws Exception { var exception = vectorizeWithError("400"); assertThat(exception) - .isInstanceOf(JsonApiException.class) - .hasFieldOrPropertyWithValue("errorCode", ErrorCodeV1.EMBEDDING_PROVIDER_CLIENT_ERROR) + .hasFieldOrPropertyWithValue( + "code", EmbeddingProviderException.Code.EMBEDDING_PROVIDER_CLIENT_ERROR.name()) .hasFieldOrPropertyWithValue( "message", - "The Embedding Provider returned a HTTP client error: Provider: nvidia; HTTP Status: 400; Error Message: {\"object\":\"list\"}"); + "Provider 'nvidia' returned a HTTP client error with HTTP 400; error message: {\"object\":\"list\"}"); } @Test @@ -136,11 +137,11 @@ public void test5xx() throws Exception { var exception = vectorizeWithError("503"); assertThat(exception) - .isInstanceOf(JsonApiException.class) - .hasFieldOrPropertyWithValue("errorCode", ErrorCodeV1.EMBEDDING_PROVIDER_SERVER_ERROR) + .hasFieldOrPropertyWithValue( + "code", EmbeddingProviderException.Code.EMBEDDING_PROVIDER_SERVER_ERROR.name()) .hasFieldOrPropertyWithValue( "message", - "The Embedding Provider returned a HTTP server error: Provider: nvidia; HTTP Status: 503; Error Message: {\"object\":\"list\"}"); + "Provider 'nvidia' returned a HTTP server error with HTTP 503; error message: {\"object\":\"list\"}"); } @Test @@ -149,11 +150,11 @@ public void testRetryError() throws Exception { var exception = vectorizeWithError("408"); assertThat(exception) - .isInstanceOf(JsonApiException.class) - .hasFieldOrPropertyWithValue("errorCode", ErrorCodeV1.EMBEDDING_PROVIDER_TIMEOUT) + .hasFieldOrPropertyWithValue( + "code", EmbeddingProviderException.Code.EMBEDDING_PROVIDER_TIMEOUT.name()) .hasFieldOrPropertyWithValue( "message", - "The Embedding Provider timed out: Provider: nvidia; HTTP Status: 408; Error Message: {\"object\":\"list\"}"); + "Provider 'nvidia' request timed out with HTTP 408; error message: {\"object\":\"list\"}"); } @Test @@ -182,12 +183,10 @@ public void testIncorrectContentTypeXML() { var exception = vectorizeWithError("application/xml"); assertThat(exception) - .isInstanceOf(JsonApiException.class) .hasFieldOrPropertyWithValue( - "errorCode", ErrorCodeV1.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE) - .hasFieldOrPropertyWithValue( - "message", - "The Embedding Provider returned an unexpected response: Expected response Content-Type ('application/json' or 'text/json') from the embedding provider but found 'application/xml'; HTTP Status: 200; The response body is: 'list'."); + "code", EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.name()) + .hasMessageContaining( + "Expected response Content-Type ('application/json' or 'text/json') from the embedding provider but found 'application/xml'; HTTP Status: 200; The response body is: 'list'."); } @Test @@ -196,26 +195,19 @@ public void testIncorrectContentTypePlainText() { var exception = vectorizeWithError("text/plain;charset=UTF-8"); assertThat(exception) - .isInstanceOf(JsonApiException.class) - .hasFieldOrPropertyWithValue( - "errorCode", ErrorCodeV1.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE) .hasFieldOrPropertyWithValue( - "message", - "The Embedding Provider returned an unexpected response: Expected response Content-Type ('application/json' or 'text/json') from the embedding provider but found 'text/plain;charset=UTF-8'; HTTP Status: 200; The response body is: 'vectors as plain text'."); + "code", EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.name()) + .hasMessageContaining( + "Expected response Content-Type ('application/json' or 'text/json') from the embedding provider but found 'text/plain;charset=UTF-8'; HTTP Status: 200; The response body is: 'vectors as plain text'."); } @Test public void testNoJsonResponse() { - var exception = vectorizeWithError("no json body"); - assertThat(exception) - .isInstanceOf(JsonApiException.class) - .hasFieldOrPropertyWithValue( - "errorCode", ErrorCodeV1.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE) .hasFieldOrPropertyWithValue( - "message", - "The Embedding Provider returned an unexpected response: No response body from the embedding provider"); + "code", EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.name()) + .hasMessageContaining("No response body from the embedding provider"); } @Test @@ -224,12 +216,10 @@ public void testEmptyJsonResponse() { var exception = vectorizeWithError("empty json body"); assertThat(exception) - .isInstanceOf(JsonApiException.class) - .hasFieldOrPropertyWithValue( - "errorCode", ErrorCodeV1.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE) .hasFieldOrPropertyWithValue( - "message", - "The Embedding Provider returned an unexpected response: Provider: nvidia; HTTP Status: 200; Error Message: ModelProvider returned empty data for model testModel"); + "code", EmbeddingProviderException.Code.EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE.name()) + .hasMessageContaining( + "Provider: nvidia; HTTP Status: 200; Error Message: The embedding provider returned empty data for model testModel"); } } } diff --git a/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/OpenAiEmbeddingClientTest.java b/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/OpenAiEmbeddingClientTest.java index 542b27854d..1011532cb0 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/OpenAiEmbeddingClientTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/service/embedding/operation/OpenAiEmbeddingClientTest.java @@ -7,8 +7,7 @@ import io.smallrye.mutiny.helpers.test.UniAssertSubscriber; import io.stargate.sgv2.jsonapi.TestConstants; import io.stargate.sgv2.jsonapi.api.request.EmbeddingCredentials; -import io.stargate.sgv2.jsonapi.exception.ErrorCodeV1; -import io.stargate.sgv2.jsonapi.exception.JsonApiException; +import io.stargate.sgv2.jsonapi.exception.EmbeddingProviderException; import io.stargate.sgv2.jsonapi.service.embedding.configuration.EmbeddingProvidersConfig; import io.stargate.sgv2.jsonapi.service.embedding.configuration.EmbeddingProvidersConfigImpl; import io.stargate.sgv2.jsonapi.service.embedding.configuration.ServiceConfigStore; @@ -149,11 +148,11 @@ public void invalidOrg() throws Exception { "some data"); assertThat(exception) - .isInstanceOf(JsonApiException.class) - .hasFieldOrPropertyWithValue("errorCode", ErrorCodeV1.EMBEDDING_PROVIDER_CLIENT_ERROR) + .hasFieldOrPropertyWithValue( + "code", EmbeddingProviderException.Code.EMBEDDING_PROVIDER_CLIENT_ERROR.name()) .hasFieldOrPropertyWithValue( "message", - "The Embedding Provider returned a HTTP client error: Provider: openai; HTTP Status: 401; Error Message: {\"object\":\"list\"}"); + "Provider 'openai' returned a HTTP client error with HTTP 401; error message: {\"object\":\"list\"}"); } @Test @@ -165,11 +164,11 @@ public void invalidProject() throws Exception { "some data"); assertThat(exception) - .isInstanceOf(JsonApiException.class) - .hasFieldOrPropertyWithValue("errorCode", ErrorCodeV1.EMBEDDING_PROVIDER_CLIENT_ERROR) + .hasFieldOrPropertyWithValue( + "code", EmbeddingProviderException.Code.EMBEDDING_PROVIDER_CLIENT_ERROR.name()) .hasFieldOrPropertyWithValue( "message", - "The Embedding Provider returned a HTTP client error: Provider: openai; HTTP Status: 401; Error Message: {\"object\":\"list\"}"); + "Provider 'openai' returned a HTTP client error with HTTP 401; error message: {\"object\":\"list\"}"); } } } diff --git a/src/test/java/io/stargate/sgv2/jsonapi/service/reranking/gateway/RerankingGatewayClientTest.java b/src/test/java/io/stargate/sgv2/jsonapi/service/reranking/gateway/RerankingGatewayClientTest.java index f6d6b7a8f4..7f88c80ef6 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/service/reranking/gateway/RerankingGatewayClientTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/service/reranking/gateway/RerankingGatewayClientTest.java @@ -143,7 +143,7 @@ void handleError() { final SchemaException apiException = SchemaException.Code.RERANKING_PROVIDER_SERVER_ERROR.get( Map.of("errorMessage", "Test fail")); - errorResponseBuilder.setErrorCode(apiException.code).setErrorMessage(apiException.getMessage()); + errorResponseBuilder.setErrorCode(apiException.code).setErrorBody(apiException.getMessage()); builder.setError(errorResponseBuilder.build()); when(rerankService.rerank(any())).thenReturn(Uni.createFrom().item(builder.build()));