@@ -199,14 +199,15 @@ def publish_batch(
199
199
200
200
total_batch_size = 0
201
201
message_contexts = []
202
- for entry in publish_batch_request_entries :
202
+ for entry_index , entry in enumerate ( publish_batch_request_entries , start = 1 ) :
203
203
message_payload = entry .get ("Message" )
204
204
message_attributes = entry .get ("MessageAttributes" , {})
205
- total_batch_size += get_total_publish_size (message_payload , message_attributes )
206
205
if message_attributes :
207
206
# if a message contains non-valid message attributes
208
207
# will fail for the first non-valid message encountered, and raise ParameterValueInvalid
209
- validate_message_attributes (message_attributes )
208
+ validate_message_attributes (message_attributes , position = entry_index )
209
+
210
+ total_batch_size += get_total_publish_size (message_payload , message_attributes )
210
211
211
212
# TODO: WRITE AWS VALIDATED
212
213
if entry .get ("MessageStructure" ) == "json" :
@@ -532,6 +533,9 @@ def publish(
532
533
f"Invalid parameter: PhoneNumber Reason: { phone_number } is not valid to publish to"
533
534
)
534
535
536
+ if message_attributes :
537
+ validate_message_attributes (message_attributes )
538
+
535
539
if get_total_publish_size (message , message_attributes ) > MAXIMUM_MESSAGE_LENGTH :
536
540
raise InvalidParameterException ("Invalid parameter: Message too long" )
537
541
@@ -579,9 +583,6 @@ def publish(
579
583
"Invalid parameter: Message Structure - JSON message body failed to parse"
580
584
)
581
585
582
- if message_attributes :
583
- validate_message_attributes (message_attributes )
584
-
585
586
if not phone_number :
586
587
# use the account to get the store from the TopicArn (you can only publish in the same region as the topic)
587
588
parsed_arn = parse_and_validate_topic_arn (topic_or_target_arn )
@@ -918,12 +919,15 @@ def validate_subscription_attribute(
918
919
)
919
920
920
921
921
- def validate_message_attributes (message_attributes : MessageAttributeMap ) -> None :
922
+ def validate_message_attributes (
923
+ message_attributes : MessageAttributeMap , position : int | None = None
924
+ ) -> None :
922
925
"""
923
926
Validate the message attributes, and raises an exception if those do not follow AWS validation
924
927
See: https://docs.aws.amazon.com/sns/latest/dg/sns-message-attributes.html
925
928
Regex from: https://stackoverflow.com/questions/40718851/regex-that-does-not-allow-consecutive-dots
926
929
:param message_attributes: the message attributes map for the message
930
+ :param position: given to give the Batch Entry position if coming from `publishBatch`
927
931
:raises: InvalidParameterValueException
928
932
:return: None
929
933
"""
@@ -934,7 +938,18 @@ def validate_message_attributes(message_attributes: MessageAttributeMap) -> None
934
938
)
935
939
validate_message_attribute_name (attr_name )
936
940
# `DataType` is a required field for MessageAttributeValue
937
- data_type = attr ["DataType" ]
941
+ if (data_type := attr .get ("DataType" )) is None :
942
+ if position :
943
+ at = f"publishBatchRequestEntries.{ position } .member.messageAttributes.{ attr_name } .member.dataType"
944
+ else :
945
+ at = f"messageAttributes.{ attr_name } .member.dataType"
946
+
947
+ raise CommonServiceException (
948
+ code = "ValidationError" ,
949
+ message = f"1 validation error detected: Value null at '{ at } ' failed to satisfy constraint: Member must not be null" ,
950
+ sender_fault = True ,
951
+ )
952
+
938
953
if data_type not in (
939
954
"String" ,
940
955
"Number" ,
@@ -943,6 +958,11 @@ def validate_message_attributes(message_attributes: MessageAttributeMap) -> None
943
958
raise InvalidParameterValueException (
944
959
f"The message attribute '{ attr_name } ' has an invalid message attribute type, the set of supported type prefixes is Binary, Number, and String."
945
960
)
961
+ if not any (attr_value .endswith ("Value" ) for attr_value in attr ):
962
+ raise InvalidParameterValueException (
963
+ f"The message attribute '{ attr_name } ' must contain non-empty message attribute value for message attribute type '{ data_type } '."
964
+ )
965
+
946
966
value_key_data_type = "Binary" if data_type .startswith ("Binary" ) else "String"
947
967
value_key = f"{ value_key_data_type } Value"
948
968
if value_key not in attr :
0 commit comments