2020-12-12 13:32:06 +01:00
use actix_web as aweb ;
2021-06-21 19:20:04 +02:00
use aweb ::error ::{ JsonPayloadError , QueryPayloadError } ;
2024-07-08 20:58:27 +02:00
use byte_unit ::{ Byte , UnitType } ;
2022-10-22 13:59:21 +02:00
use meilisearch_types ::document_formats ::{ DocumentFormatError , PayloadType } ;
2022-06-06 12:38:46 +02:00
use meilisearch_types ::error ::{ Code , ErrorCode , ResponseError } ;
2023-01-17 13:51:07 +01:00
use meilisearch_types ::index_uid ::{ IndexUid , IndexUidFormatError } ;
2024-09-12 17:47:00 +02:00
use meilisearch_types ::milli ::OrderBy ;
2022-10-11 17:42:43 +02:00
use serde_json ::Value ;
2022-09-22 20:02:55 +02:00
use tokio ::task ::JoinError ;
2021-06-14 21:26:35 +02:00
2021-09-30 10:26:30 +02:00
#[ derive(Debug, thiserror::Error) ]
pub enum MeilisearchHttpError {
2021-10-05 13:30:53 +02:00
#[ error( " A Content-Type header is missing. Accepted values for the Content-Type header are: {} " ,
2021-10-26 19:36:48 +02:00
. 0. iter ( ) . map ( | s | format! ( " ` {} ` " , s ) ) . collect ::< Vec < _ > > ( ) . join ( " , " ) ) ]
2021-10-05 13:30:53 +02:00
MissingContentType ( Vec < String > ) ,
2024-02-08 09:43:39 +01:00
#[ error( " The `/logs/stream` route is currently in use by someone else. " ) ]
2024-01-29 17:56:43 +01:00
AlreadyUsedLogRoute ,
2023-02-16 13:12:18 +01:00
#[ error( " The Content-Type `{0}` does not support the use of a csv delimiter. The csv delimiter can only be used with the Content-Type `text/csv`. " ) ]
CsvDelimiterWithWrongContentType ( String ) ,
2021-10-05 13:30:53 +02:00
#[ error(
2021-10-26 19:36:48 +02:00
" The Content-Type `{0}` is invalid. Accepted values for the Content-Type header are: {} " ,
. 1. iter ( ) . map ( | s | format! ( " ` {} ` " , s ) ) . collect ::< Vec < _ > > ( ) . join ( " , " )
2021-10-05 13:30:53 +02:00
) ]
InvalidContentType ( String , Vec < String > ) ,
2022-10-11 17:42:43 +02:00
#[ error( " Document `{0}` not found. " ) ]
DocumentNotFound ( String ) ,
2023-05-02 17:46:04 +02:00
#[ error( " Sending an empty filter is forbidden. " ) ]
EmptyFilter ,
2024-07-17 11:13:37 +02:00
#[ error( " Invalid syntax for the filter parameter: `expected {}, found: {1}`. " , .0.join( " , " )) ]
InvalidExpression ( & 'static [ & 'static str ] , Value ) ,
2024-09-11 11:25:26 +02:00
#[ error( " Using `federationOptions` is not allowed in a non-federated search. \n - Hint: remove `federationOptions` from query #{0} or add `federation` to the request. " ) ]
2024-07-11 16:31:44 +02:00
FederationOptionsInNonFederatedRequest ( usize ) ,
2024-09-11 11:25:26 +02:00
#[ error( " Inside `.queries[{0}]`: Using pagination options is not allowed in federated queries. \n - Hint: remove `{1}` from query #{0} or remove `federation` from the request \n - Hint: pass `federation.limit` and `federation.offset` for pagination in federated search " ) ]
2024-07-11 16:31:44 +02:00
PaginationInFederatedQuery ( usize , & 'static str ) ,
2024-09-17 10:08:21 +02:00
#[ error( " Inside `.queries[{0}]`: Using facet options is not allowed in federated queries. \n - Hint: remove `facets` from query #{0} or remove `federation` from the request \n - Hint: pass `federation.facetsByIndex.{1}: {2:?}` for facets in federated search " ) ]
FacetsInFederatedQuery ( usize , String , Vec < String > ) ,
2024-09-17 17:39:51 +02:00
#[ error( " Inconsistent order for values in facet `{facet}`: index `{previous_uid}` orders {previous_facet_order}, but index `{current_uid}` orders {index_facet_order}. \n - Hint: Remove `federation.mergeFacets` or change `faceting.sortFacetValuesBy` to be consistent in settings. " ) ]
2024-09-12 17:47:00 +02:00
InconsistentFacetOrder {
facet : String ,
previous_facet_order : OrderBy ,
previous_uid : String ,
index_facet_order : OrderBy ,
current_uid : String ,
} ,
2022-10-22 13:59:21 +02:00
#[ error( " A {0} payload is missing. " ) ]
MissingPayload ( PayloadType ) ,
2024-03-26 17:53:37 +01:00
#[ error( " Too many search requests running at the same time: {0}. Retry after 10s. " ) ]
TooManySearchRequests ( usize ) ,
2024-03-27 17:34:49 +01:00
#[ error( " Internal error: Search limiter is down. " ) ]
2024-03-26 15:56:43 +01:00
SearchLimiterIsDown ,
2024-07-08 20:58:27 +02:00
#[ error( " The provided payload reached the size limit. The maximum accepted payload size is {}. " , Byte::from_u64(*.0 as u64).get_appropriate_unit(UnitType::Binary)) ]
2023-05-09 20:00:03 +02:00
PayloadTooLarge ( usize ) ,
2023-01-18 17:26:48 +01:00
#[ error( " Two indexes must be given for each swap. The list `[{}]` contains {} indexes. " ,
. 0. iter ( ) . map ( | uid | format! ( " \" {uid} \" " ) ) . collect ::< Vec < _ > > ( ) . join ( " , " ) , . 0. len ( )
2022-10-26 12:57:29 +02:00
) ]
2023-01-17 13:51:07 +01:00
SwapIndexPayloadWrongLength ( Vec < IndexUid > ) ,
2022-10-11 17:42:43 +02:00
#[ error(transparent) ]
2022-10-22 14:19:56 +02:00
IndexUid ( #[ from ] IndexUidFormatError ) ,
#[ error(transparent) ]
2022-10-11 17:42:43 +02:00
SerdeJson ( #[ from ] serde_json ::Error ) ,
#[ error(transparent) ]
HeedError ( #[ from ] meilisearch_types ::heed ::Error ) ,
2022-09-22 20:02:55 +02:00
#[ error(transparent) ]
IndexScheduler ( #[ from ] index_scheduler ::Error ) ,
#[ error(transparent) ]
2022-10-11 17:42:43 +02:00
Milli ( #[ from ] meilisearch_types ::milli ::Error ) ,
#[ error(transparent) ]
2022-09-22 20:02:55 +02:00
Payload ( #[ from ] PayloadError ) ,
#[ error(transparent) ]
2022-09-27 16:33:37 +02:00
FileStore ( #[ from ] file_store ::Error ) ,
2022-09-22 20:02:55 +02:00
#[ error(transparent) ]
2022-09-27 16:33:37 +02:00
DocumentFormat ( #[ from ] DocumentFormatError ) ,
2022-09-22 20:02:55 +02:00
#[ error(transparent) ]
Join ( #[ from ] JoinError ) ,
2024-09-17 16:27:35 +02:00
#[ error( " Invalid request: missing `hybrid` parameter when `vector` is present. " ) ]
2023-12-14 12:42:37 +01:00
MissingSearchHybrid ,
2021-09-30 10:26:30 +02:00
}
impl ErrorCode for MeilisearchHttpError {
fn error_code ( & self ) -> Code {
match self {
2021-10-05 13:30:53 +02:00
MeilisearchHttpError ::MissingContentType ( _ ) = > Code ::MissingContentType ,
2024-01-29 17:56:43 +01:00
MeilisearchHttpError ::AlreadyUsedLogRoute = > Code ::BadRequest ,
2023-02-16 13:12:18 +01:00
MeilisearchHttpError ::CsvDelimiterWithWrongContentType ( _ ) = > Code ::InvalidContentType ,
2022-10-22 13:59:21 +02:00
MeilisearchHttpError ::MissingPayload ( _ ) = > Code ::MissingPayload ,
2021-10-05 13:30:53 +02:00
MeilisearchHttpError ::InvalidContentType ( _ , _ ) = > Code ::InvalidContentType ,
2022-10-11 17:42:43 +02:00
MeilisearchHttpError ::DocumentNotFound ( _ ) = > Code ::DocumentNotFound ,
2023-05-24 11:53:16 +02:00
MeilisearchHttpError ::EmptyFilter = > Code ::InvalidDocumentFilter ,
2023-01-09 18:59:09 +01:00
MeilisearchHttpError ::InvalidExpression ( _ , _ ) = > Code ::InvalidSearchFilter ,
2023-05-09 20:00:03 +02:00
MeilisearchHttpError ::PayloadTooLarge ( _ ) = > Code ::PayloadTooLarge ,
2024-03-26 17:53:37 +01:00
MeilisearchHttpError ::TooManySearchRequests ( _ ) = > Code ::TooManySearchRequests ,
2024-03-26 15:56:43 +01:00
MeilisearchHttpError ::SearchLimiterIsDown = > Code ::Internal ,
2023-01-05 21:25:20 +01:00
MeilisearchHttpError ::SwapIndexPayloadWrongLength ( _ ) = > Code ::InvalidSwapIndexes ,
2022-10-22 14:19:56 +02:00
MeilisearchHttpError ::IndexUid ( e ) = > e . error_code ( ) ,
2022-10-11 17:42:43 +02:00
MeilisearchHttpError ::SerdeJson ( _ ) = > Code ::Internal ,
MeilisearchHttpError ::HeedError ( _ ) = > Code ::Internal ,
2022-09-22 20:02:55 +02:00
MeilisearchHttpError ::IndexScheduler ( e ) = > e . error_code ( ) ,
2022-10-11 17:42:43 +02:00
MeilisearchHttpError ::Milli ( e ) = > e . error_code ( ) ,
2022-09-22 20:02:55 +02:00
MeilisearchHttpError ::Payload ( e ) = > e . error_code ( ) ,
2022-09-27 16:33:37 +02:00
MeilisearchHttpError ::FileStore ( _ ) = > Code ::Internal ,
2022-09-22 20:02:55 +02:00
MeilisearchHttpError ::DocumentFormat ( e ) = > e . error_code ( ) ,
MeilisearchHttpError ::Join ( _ ) = > Code ::Internal ,
2023-12-14 12:42:37 +01:00
MeilisearchHttpError ::MissingSearchHybrid = > Code ::MissingSearchHybrid ,
2024-07-11 16:31:44 +02:00
MeilisearchHttpError ::FederationOptionsInNonFederatedRequest ( _ ) = > {
Code ::InvalidMultiSearchFederationOptions
}
MeilisearchHttpError ::PaginationInFederatedQuery ( _ , _ ) = > {
Code ::InvalidMultiSearchQueryPagination
}
2024-09-17 10:08:21 +02:00
MeilisearchHttpError ::FacetsInFederatedQuery ( .. ) = > Code ::InvalidMultiSearchQueryFacets ,
2024-09-12 17:47:00 +02:00
MeilisearchHttpError ::InconsistentFacetOrder { .. } = > {
Code ::InvalidMultiSearchFacetOrder
}
2021-09-30 10:26:30 +02:00
}
}
}
2021-10-06 11:49:34 +02:00
impl From < MeilisearchHttpError > for aweb ::Error {
fn from ( other : MeilisearchHttpError ) -> Self {
aweb ::Error ::from ( ResponseError ::from ( other ) )
}
}
2022-09-22 20:02:55 +02:00
impl From < aweb ::error ::PayloadError > for MeilisearchHttpError {
fn from ( error : aweb ::error ::PayloadError ) -> Self {
2024-06-21 00:55:09 +02:00
match error {
2024-06-21 01:14:26 +02:00
aweb ::error ::PayloadError ::Incomplete ( _ ) = > MeilisearchHttpError ::Payload (
PayloadError ::Payload ( ActixPayloadError ::IncompleteError ) ,
) ,
_ = > MeilisearchHttpError ::Payload ( PayloadError ::Payload (
ActixPayloadError ::OtherError ( error ) ,
) ) ,
2024-06-21 00:55:09 +02:00
}
2022-09-22 20:02:55 +02:00
}
}
2024-06-21 00:55:09 +02:00
#[ derive(Debug, thiserror::Error) ]
pub enum ActixPayloadError {
2024-06-25 19:36:29 +02:00
#[ error( " The provided payload is incomplete and cannot be parsed " ) ]
2024-06-21 00:55:09 +02:00
IncompleteError ,
#[ error(transparent) ]
2024-06-21 01:14:26 +02:00
OtherError ( aweb ::error ::PayloadError ) ,
2024-06-21 00:55:09 +02:00
}
2021-11-08 18:31:27 +01:00
#[ derive(Debug, thiserror::Error) ]
2021-06-21 19:20:04 +02:00
pub enum PayloadError {
2022-09-22 20:02:55 +02:00
#[ error(transparent) ]
2024-06-21 00:55:09 +02:00
Payload ( ActixPayloadError ) ,
2022-09-22 20:02:55 +02:00
#[ error(transparent) ]
2021-06-21 19:20:04 +02:00
Json ( JsonPayloadError ) ,
2022-09-22 20:02:55 +02:00
#[ error(transparent) ]
2021-06-21 19:20:04 +02:00
Query ( QueryPayloadError ) ,
2021-11-08 18:31:27 +01:00
#[ error( " The json payload provided is malformed. `{0}`. " ) ]
MalformedPayload ( serde_json ::error ::Error ) ,
#[ error( " A json payload is missing. " ) ]
MissingPayload ,
2022-12-13 15:07:35 +01:00
#[ error( " Error while receiving the playload. `{0}`. " ) ]
ReceivePayload ( Box < dyn std ::error ::Error + Send + Sync + 'static > ) ,
2021-06-21 19:20:04 +02:00
}
impl ErrorCode for PayloadError {
fn error_code ( & self ) -> Code {
match self {
2022-09-22 20:02:55 +02:00
PayloadError ::Payload ( e ) = > match e {
2024-06-21 00:55:09 +02:00
ActixPayloadError ::IncompleteError = > Code ::BadRequest ,
ActixPayloadError ::OtherError ( error ) = > match error {
aweb ::error ::PayloadError ::EncodingCorrupted = > Code ::Internal ,
aweb ::error ::PayloadError ::Overflow = > Code ::PayloadTooLarge ,
aweb ::error ::PayloadError ::UnknownLength = > Code ::Internal ,
aweb ::error ::PayloadError ::Http2Payload ( _ ) = > Code ::Internal ,
aweb ::error ::PayloadError ::Io ( _ ) = > Code ::Internal ,
_ = > todo! ( ) ,
2024-06-21 01:14:26 +02:00
} ,
2022-09-22 20:02:55 +02:00
} ,
2021-06-21 19:20:04 +02:00
PayloadError ::Json ( err ) = > match err {
2021-09-08 12:34:56 +02:00
JsonPayloadError ::Overflow { .. } = > Code ::PayloadTooLarge ,
2021-06-21 19:20:04 +02:00
JsonPayloadError ::ContentType = > Code ::UnsupportedMediaType ,
2021-06-23 14:48:33 +02:00
JsonPayloadError ::Payload ( aweb ::error ::PayloadError ::Overflow ) = > {
Code ::PayloadTooLarge
}
2021-11-08 18:31:27 +01:00
JsonPayloadError ::Payload ( _ ) = > Code ::BadRequest ,
JsonPayloadError ::Deserialize ( _ ) = > Code ::BadRequest ,
2021-06-21 19:20:04 +02:00
JsonPayloadError ::Serialize ( _ ) = > Code ::Internal ,
_ = > Code ::Internal ,
} ,
PayloadError ::Query ( err ) = > match err {
QueryPayloadError ::Deserialize ( _ ) = > Code ::BadRequest ,
_ = > Code ::Internal ,
} ,
2021-11-08 18:31:27 +01:00
PayloadError ::MissingPayload = > Code ::MissingPayload ,
PayloadError ::MalformedPayload ( _ ) = > Code ::MalformedPayload ,
2022-12-13 15:07:35 +01:00
PayloadError ::ReceivePayload ( _ ) = > Code ::Internal ,
2021-06-21 19:20:04 +02:00
}
}
}
impl From < JsonPayloadError > for PayloadError {
fn from ( other : JsonPayloadError ) -> Self {
2021-11-08 18:31:27 +01:00
match other {
JsonPayloadError ::Deserialize ( e )
if e . classify ( ) = = serde_json ::error ::Category ::Eof
& & e . line ( ) = = 1
& & e . column ( ) = = 0 = >
{
Self ::MissingPayload
}
JsonPayloadError ::Deserialize ( e )
if e . classify ( ) ! = serde_json ::error ::Category ::Data = >
{
Self ::MalformedPayload ( e )
}
_ = > Self ::Json ( other ) ,
}
2021-06-21 19:20:04 +02:00
}
}
impl From < QueryPayloadError > for PayloadError {
fn from ( other : QueryPayloadError ) -> Self {
Self ::Query ( other )
}
}
2021-10-06 11:49:34 +02:00
impl From < PayloadError > for aweb ::Error {
fn from ( other : PayloadError ) -> Self {
aweb ::Error ::from ( ResponseError ::from ( other ) )
}
2021-06-21 18:42:47 +02:00
}