Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,24 @@ public enum Code implements ErrorCode<DocumentException> {
DOCUMENT_ALREADY_EXISTS,
// Internal error: does it belong here?
DOCUMENT_FROM_DB_UNPARSEABLE,
DOCUMENT_LEXICAL_CONTENT_TOO_BIG,
DOCUMENT_REPLACE_DIFFERENT_DOCID,

INVALID_COLUMN_VALUES,
MISSING_PRIMARY_KEY_COLUMNS,

SHRED_BAD_BINARY_VECTOR_VALUE,
Copy link
Contributor

Choose a reason for hiding this comment

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

we dont have any BAD error codes in V2 errors - we can let them through and then I can fix in a follow up ? as in they take some thinking do we want to do that now ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, postpone for now to give us more time to think it through.

SHRED_BAD_DOCID_TYPE,
SHRED_BAD_DOCID_VALUE,
SHRED_BAD_DOCUMENT_TYPE,
SHRED_BAD_DOCUMENT_VECTOR_TYPE,
SHRED_BAD_DOCUMENT_LEXICAL_TYPE,
SHRED_BAD_EJSON_VALUE,
SHRED_BAD_FIELD_NAME, // from ErrorV1.SHRED_DOC_KEY_NAME_VIOLATION
SHRED_BAD_VECTOR_SIZE,
SHRED_BAD_VECTOR_VALUE,
SHRED_DOC_LIMIT_VIOLATION,

UNKNOWN_TABLE_COLUMNS,
UNSUPPORTED_COLUMN_TYPES,
UNSUPPORTED_VECTORIZE_CONFIGURATIONS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,6 @@ public enum ErrorCodeV1 {
EMBEDDING_PROVIDER_UNEXPECTED_RESPONSE("The Embedding Provider returned an unexpected response"),
EMBEDDING_PROVIDER_API_KEY_MISSING("The Embedding Provider API key is missing"),

// Really Bad, generic name: but only used for EmbeddingProvidersConfig validation issues
INVALID_PARAMETER_VALIDATION_TYPE("Invalid Parameter Validation Type"),

SHRED_BAD_BINARY_VECTOR_VALUE("Bad binary vector value to shred"),

SHRED_BAD_DOCID_TYPE("Bad type for '_id' property"),

SHRED_BAD_DOCID_EMPTY_STRING("Bad value for '_id' property: empty String not allowed"),

SHRED_BAD_DOCUMENT_TYPE("Bad document type to shred"),

SHRED_BAD_DOCUMENT_VECTOR_TYPE("Bad $vector document type to shred "),

SHRED_BAD_DOCUMENT_VECTORIZE_TYPE("Bad $vectorize document type to shred "),

SHRED_BAD_DOCUMENT_LEXICAL_TYPE("Bad type for $lexical content to shred"),

SHRED_BAD_EJSON_VALUE("Bad JSON Extension value"),

SHRED_BAD_VECTOR_SIZE("$vector value can't be empty"),

SHRED_BAD_VECTOR_VALUE("$vector value needs to be array of numbers"),

SHRED_DOC_KEY_NAME_VIOLATION("Document field name invalid"),
SHRED_DOC_LIMIT_VIOLATION("Document size limitation violated"),

// CreateCollection error codes:

EXISTING_TABLE_NOT_DATA_API_COLLECTION("Existing table is not a valid Data API collection"),
Expand Down Expand Up @@ -100,9 +74,6 @@ public enum ErrorCodeV1 {
VECTORIZE_CREDENTIAL_INVALID("Invalid credential name for vectorize"),
VECTORIZECONFIG_CHECK_FAIL("Internal server error: VectorizeDefinition check fail"),

LEXICAL_CONTENT_TOO_BIG(
"Lexical content is too big, please use a smaller value for the $lexical field"),

HYBRID_FIELD_CONFLICT(
"The '$hybrid' field cannot be used with '$lexical', '$vector', or '$vectorize'."),
HYBRID_FIELD_UNSUPPORTED_VALUE_TYPE("Unsupported JSON value type for '$hybrid' field"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ public class JsonApiException extends RuntimeException implements Supplier<Comma
ErrorScope.SCHEMA,
new HashSet<>() {
{
add(INVALID_PARAMETER_VALIDATION_TYPE);
add(INVALID_REQUEST);
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ private static CommandResult.Error handleQueryValidationException(
// [data-api#2068]: Need to convert Lexical-value-too-big failure to something more meaningful
if (message.contains(
"analyzed size for column query_lexical_value exceeds the cumulative limit for index")) {
return ErrorCodeV1.LEXICAL_CONTENT_TOO_BIG
.toApiException()
return DocumentException.Code.DOCUMENT_LEXICAL_CONTENT_TOO_BIG
.get()
.getCommandResultError(Response.Status.OK);
}
return ErrorCodeV1.INVALID_QUERY
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
import io.stargate.sgv2.jsonapi.api.model.command.CommandResult;
import io.stargate.sgv2.jsonapi.api.model.command.tracing.RequestTracing;
import io.stargate.sgv2.jsonapi.config.OperationsConfig;
import io.stargate.sgv2.jsonapi.exception.APIException;
import io.stargate.sgv2.jsonapi.exception.APIExceptionCommandErrorBuilder;
import io.stargate.sgv2.jsonapi.exception.ErrorCodeV1;
import io.stargate.sgv2.jsonapi.exception.JsonApiException;
import io.stargate.sgv2.jsonapi.exception.*;
import jakarta.inject.Inject;
import jakarta.ws.rs.NotAllowedException;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.NotSupportedException;
import jakarta.ws.rs.WebApplicationException;
import java.util.Map;
import org.jboss.resteasy.reactive.RestResponse;
import org.jboss.resteasy.reactive.server.ServerExceptionMapper;

Expand All @@ -32,7 +30,9 @@ public RestResponse<CommandResult> webApplicationExceptionMapper(WebApplicationE
// and if we have StreamConstraintsException, re-create as ApiException
if (toReport instanceof StreamConstraintsException) {
// but leave out the root cause, as it is not useful
toReport = ErrorCodeV1.SHRED_DOC_LIMIT_VIOLATION.toApiException(toReport.getMessage());
toReport =
DocumentException.Code.SHRED_DOC_LIMIT_VIOLATION.get(
Map.of("errorMessage", toReport.getMessage()));
}

// V2 Error are returned as APIException, this is required to translate the exception to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithConverter;
import io.smallrye.config.WithDefault;
import io.stargate.sgv2.jsonapi.exception.ErrorCodeV1;
import io.stargate.sgv2.jsonapi.service.provider.ApiModelSupport;
import jakarta.annotation.Nullable;
import jakarta.inject.Inject;
Expand Down Expand Up @@ -207,7 +206,10 @@ public static ValidationType fromString(String type) {
} else if (type.equals("options")) {
return OPTIONS;
}
throw ErrorCodeV1.INVALID_PARAMETER_VALIDATION_TYPE.toApiException(type);
throw new IllegalArgumentException(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

One-off failure not to be directly exposed: caller will wrap/convert validation problems in more centralized way.

Copy link
Contributor

Choose a reason for hiding this comment

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

I am guessing we only need this stuff because of the EGW and the trouble we have with configs ?

"Invalid `ValidationType` value ('"
+ type
+ "') for `EmbeddingProvidersConfig`: expected either 'numericRange' or 'options'");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
import io.quarkus.runtime.annotations.RegisterForReflection;
import io.stargate.sgv2.jsonapi.api.model.command.clause.filter.JsonType;
import io.stargate.sgv2.jsonapi.config.constants.DocumentConstants;
import io.stargate.sgv2.jsonapi.exception.ErrorCodeV1;
import io.stargate.sgv2.jsonapi.exception.DocumentException;
import io.stargate.sgv2.jsonapi.exception.JsonApiException;
import io.stargate.sgv2.jsonapi.service.shredding.DocRowIdentifer;
import io.stargate.sgv2.jsonapi.util.JsonUtil;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

Expand Down Expand Up @@ -78,20 +79,26 @@ static DocumentId fromJson(JsonNode node) {
return fromExtensionType(extType, valueNode);
}
}
throw ErrorCodeV1.SHRED_BAD_DOCID_TYPE.toApiException(
"unrecognized JSON extension type '%s'", node.fieldNames().next());
}
throw ErrorCodeV1.SHRED_BAD_DOCID_TYPE.toApiException(
"Document Id must be a JSON String, Number, Boolean, EJSON-Encoded Date Object or NULL instead got %s: %s",
node.getNodeType(), node.toString());
throw DocumentException.Code.SHRED_BAD_DOCID_TYPE.get(
Map.of(
"errorMessage",
"unrecognized JSON extension type '%s'".formatted(node.fieldNames().next())));
}
throw DocumentException.Code.SHRED_BAD_DOCID_TYPE.get(
Map.of(
"errorMessage",
"Document Id must be a JSON String, Number, Boolean, EJSON-Encoded Date Object or null instead got %s: %s"
.formatted(JsonUtil.nodeTypeAsString(node), node.toString())));
}

static DocumentId fromDatabase(int typeId, String documentIdAsText) {
JsonType type = DocumentConstants.KeyTypeId.getJsonType(typeId);
if (type == null) {
throw ErrorCodeV1.SHRED_BAD_DOCID_TYPE.toApiException(
"Document Id must be a JSON String(1), Number(2), Boolean(3), NULL(4) or Date(5) instead got %d",
typeId);
throw DocumentException.Code.SHRED_BAD_DOCID_TYPE.get(
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 an error when the DB has corrupted / invalid data, the errors above are from a request.

So there may be some confusion here, it's not a REQUEST family error (which DocumentException is) it is a SERVER family error.

It would be something like DatabaseException.Code.UNEXPECTED_DOCUMENT_ID_TYPE - which does not exists.

Do we want to let this through and I can followup ?

Same for all in this function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch! Yes, agreed, I blindly made it DocumentException not paying attention.
So yes, DatabaseException.Code.UNEXPECTED_DOCUMENT_ID_TYPE: to change before merging.

Map.of(
"errorMessage",
"Document Id must be a JSON String(1), Number(2), Boolean(3), null(4) or Date(5) instead got %d"
.formatted(typeId)));
}
switch (type) {
case BOOLEAN -> {
Expand All @@ -101,9 +108,11 @@ static DocumentId fromDatabase(int typeId, String documentIdAsText) {
case "false":
return fromBoolean(false);
}
throw ErrorCodeV1.SHRED_BAD_DOCID_TYPE.toApiException(
"Document Id type Boolean stored as invalid String '%s' (must be 'true' or 'false')",
documentIdAsText);
throw DocumentException.Code.SHRED_BAD_DOCID_TYPE.get(
Map.of(
"errorMessage",
"Document Id type Boolean stored as invalid String '%s' (must be 'true' or 'false')"
.formatted(documentIdAsText)));
}
case NULL -> {
return fromNull();
Expand All @@ -112,9 +121,11 @@ static DocumentId fromDatabase(int typeId, String documentIdAsText) {
try {
return fromNumber(new BigDecimal(documentIdAsText));
} catch (NumberFormatException e) {
throw ErrorCodeV1.SHRED_BAD_DOCID_TYPE.toApiException(
"Document Id type Number stored as invalid String '%s' (not a valid Number)",
documentIdAsText);
throw DocumentException.Code.SHRED_BAD_DOCID_TYPE.get(
Map.of(
"errorMessage",
"Document Id type Number stored as invalid String '%s' (not a valid Number)"
.formatted(documentIdAsText)));
}
}
case STRING -> {
Expand All @@ -125,13 +136,16 @@ static DocumentId fromDatabase(int typeId, String documentIdAsText) {
long ts = Long.parseLong(documentIdAsText);
return fromTimestamp(ts);
} catch (NumberFormatException e) {
throw ErrorCodeV1.SHRED_BAD_DOCID_TYPE.toApiException(
"Document Id type Date stored as invalid String '%s' (needs to be Number)",
documentIdAsText);
throw DocumentException.Code.SHRED_BAD_DOCID_TYPE.get(
Map.of(
"errorMessage",
"Document Id type Date stored as invalid String '%s' (needs to be Number)"
.formatted(documentIdAsText)));
}
}
}
throw ErrorCodeV1.SHRED_BAD_DOCID_TYPE.toApiException();
throw DocumentException.Code.SHRED_BAD_DOCID_TYPE.get(
Map.of("errorMessage", "unknown `JsonType`: '%s'".formatted(type)));
}

static DocumentId fromBoolean(boolean key) {
Expand All @@ -150,7 +164,8 @@ static DocumentId fromNumber(BigDecimal key) {
static DocumentId fromString(String key) {
key = Objects.requireNonNull(key);
if (key.isEmpty()) {
throw ErrorCodeV1.SHRED_BAD_DOCID_EMPTY_STRING.toApiException();
throw DocumentException.Code.SHRED_BAD_DOCID_VALUE.get(
Map.of("errorMessage", "empty String not allowed"));
}
return new StringId(key);
}
Expand All @@ -172,7 +187,7 @@ static DocumentId fromExtensionType(JsonExtensionType extType, JsonNode valueNod
Object rawId = JsonUtil.extractExtendedValueUnwrapped(extType, valueNode);
return new ExtensionTypeId(extType, String.valueOf(rawId));
} catch (JsonApiException e) {
throw ErrorCodeV1.SHRED_BAD_DOCID_TYPE.toApiException(e.getMessage());
throw DocumentException.Code.SHRED_BAD_DOCID_TYPE.get(Map.of("errorMessage", e.getMessage()));
}
}

Expand Down
Loading