diff --git a/lib/api/src/conversions/vectors.rs b/lib/api/src/conversions/vectors.rs index 1c6720bbe3..4e18a3189e 100644 --- a/lib/api/src/conversions/vectors.rs +++ b/lib/api/src/conversions/vectors.rs @@ -15,6 +15,12 @@ fn convert_to_plain_multi_vector( data: Vec, vectors_count: usize, ) -> Result { + if vectors_count == 0 || data.is_empty() { + return Err(OperationError::validation_error(format!( + "Empty multi-vector data with vectors count: {vectors_count}" + ))); + } + let dim = data.len() / vectors_count; if dim * vectors_count != data.len() { return Err(OperationError::validation_error(format!( diff --git a/lib/common/common/src/validation.rs b/lib/common/common/src/validation.rs index 0bb372a8fc..740bf03552 100644 --- a/lib/common/common/src/validation.rs +++ b/lib/common/common/src/validation.rs @@ -302,6 +302,14 @@ pub fn validate_multi_vector_len( return Err(errors); } + if flatten_dense_vector.is_empty() { + let mut errors = ValidationErrors::default(); + let mut err = ValidationError::new("empty_multi_vector"); + err.add_param(Cow::from("message"), &"multi vector must not be empty"); + errors.add("data", err); + return Err(errors); + } + let dense_vector_len = flatten_dense_vector.len(); if dense_vector_len >= MAX_MULTIVECTOR_FLATTENED_LEN { let mut errors = ValidationErrors::default(); @@ -328,6 +336,17 @@ pub fn validate_multi_vector_len( mod tests { use super::*; + #[test] + fn test_validate_multi_vector_len_rejects_empty_data() { + // Regression: empty flattened data with a positive vectors_count must be + // rejected. Previously this returned Ok (0.is_multiple_of(N) == true), and + // the value then reached convert_to_plain_multi_vector, which builds + // chunks(dim) with dim == 0 and panics on the gRPC upsert path. + assert!(validate_multi_vector_len(2, &[]).is_err()); + // A non-empty, consistent multivector still validates. + assert!(validate_multi_vector_len(2, &[1.0, 2.0, 3.0, 4.0]).is_ok()); + } + #[test] fn test_validate_range_generic() { assert!(validate_range_generic(u64::MIN, None, None).is_ok());