@@ -764,6 +764,96 @@ def test_json_protocol_error_serialization_with_shaped_default_members_on_root()
764764 assert "message" not in parsed_body
765765
766766
767+ def test_json_protocol_error_serialization_empty_message ():
768+ # if the exception message is not passed when instantiating the exception, the message attribute will be set to
769+ # an empty string "". This is not serialized if the message field is not a required member
770+ exception = TransactionCanceledException ()
771+
772+ response = _botocore_error_serializer_integration_test (
773+ "dynamodb" ,
774+ "ExecuteTransaction" ,
775+ exception ,
776+ "TransactionCanceledException" ,
777+ 400 ,
778+ "" ,
779+ )
780+ assert "message" not in response
781+
782+
783+ @pytest .mark .parametrize ("empty_value" , ("" , None ))
784+ def test_json_protocol_error_serialization_with_empty_non_required_members (empty_value ):
785+ class _ResourceNotFoundException (ServiceException ):
786+ code : str = "ResourceNotFoundException"
787+ sender_fault : bool = True
788+ status_code : int = 404
789+ ResourceType : str | None
790+ ResourceId : str | None
791+
792+ exception = _ResourceNotFoundException ("Not Found" , ResourceType = "" )
793+
794+ response = _botocore_error_serializer_integration_test (
795+ "arc-region-switch" ,
796+ "ApprovePlanExecutionStep" ,
797+ exception ,
798+ "ResourceNotFoundException" ,
799+ 404 ,
800+ "Not Found" ,
801+ protocol = "json" ,
802+ )
803+ assert "ResourceType" not in response
804+
805+
806+ def test_json_protocol_error_serialization_falsy_non_required_members ():
807+ # if the exception message is not passed, an empty message will be passed as an empty string `""`
808+ exception = TransactionCanceledException ("Exception message!" , CancellationReasons = [])
809+
810+ response = _botocore_error_serializer_integration_test (
811+ "dynamodb" ,
812+ "ExecuteTransaction" ,
813+ exception ,
814+ "TransactionCanceledException" ,
815+ 400 ,
816+ "Exception message!" ,
817+ Message = "Exception message!" ,
818+ )
819+ assert "CancellationReasons" not in response
820+
821+
822+ @pytest .mark .parametrize ("empty_value" , ("" , None ))
823+ def test_json_protocol_error_serialization_with_empty_required_members (empty_value ):
824+ class _ResourceNotFoundException (ServiceException ):
825+ code : str = "ResourceNotFoundException"
826+ sender_fault : bool = False
827+ status_code : int = 404
828+ resourceId : str
829+ resourceType : str
830+
831+ resource_type = "test"
832+ exception = _ResourceNotFoundException (
833+ "Exception message!" ,
834+ resourceType = resource_type ,
835+ resourceId = empty_value ,
836+ )
837+ expected_exception_values = {
838+ "resourceType" : resource_type ,
839+ }
840+ # if the value is None, it is not serialized, even if required
841+ # but if it is an empty string, it will be
842+ if empty_value is not None :
843+ expected_exception_values ["resourceId" ] = ""
844+
845+ response = _botocore_error_serializer_integration_test (
846+ "verifiedpermissions" ,
847+ "IsAuthorizedWithToken" ,
848+ exception ,
849+ "ResourceNotFoundException" ,
850+ 404 ,
851+ "Exception message!" ,
852+ ** expected_exception_values ,
853+ )
854+ assert "" not in response
855+
856+
767857def test_rest_json_protocol_error_serialization_with_additional_members ():
768858 class NotFoundException (ServiceException ):
769859 code : str = "NotFoundException"
@@ -929,6 +1019,48 @@ class _ResourceNotFoundException(ServiceException):
9291019 assert serialized_response .headers ["Smithy-Protocol" ] == "rpc-v2-cbor"
9301020
9311021
1022+ @pytest .mark .parametrize ("empty_value" , ("" , None ))
1023+ def test_rpc_v2_cbor_protocol_error_serialization_with_empty_required_members (empty_value ):
1024+ class AccessDeniedException (ServiceException ):
1025+ code : str = "AccessDeniedException"
1026+ sender_fault : bool = True
1027+ status_code : int = 403
1028+
1029+ exception = AccessDeniedException ("" )
1030+
1031+ _botocore_error_serializer_integration_test (
1032+ "arc-region-switch" ,
1033+ "ApprovePlanExecutionStep" ,
1034+ exception ,
1035+ "AccessDeniedException" ,
1036+ 403 ,
1037+ "" ,
1038+ )
1039+
1040+
1041+ @pytest .mark .parametrize ("empty_value" , ("" , None ))
1042+ def test_rpc_v2_cbor_protocol_error_serialization_with_empty_non_required_members (empty_value ):
1043+ class _ResourceNotFoundException (ServiceException ):
1044+ code : str = "ResourceNotFoundException"
1045+ sender_fault : bool = True
1046+ status_code : int = 404
1047+ ResourceType : str | None
1048+ ResourceId : str | None
1049+
1050+ exception = _ResourceNotFoundException ("Not Found" , ResourceType = "" )
1051+
1052+ response = _botocore_error_serializer_integration_test (
1053+ "arc-region-switch" ,
1054+ "ApprovePlanExecutionStep" ,
1055+ exception ,
1056+ "ResourceNotFoundException" ,
1057+ 404 ,
1058+ "Not Found" ,
1059+ protocol = "smithy-rpc-v2-cbor" ,
1060+ )
1061+ assert "ResourceType" not in response
1062+
1063+
9321064def test_json_protocol_content_type_1_0 ():
9331065 """AppRunner defines the jsonVersion 1.0, therefore the Content-Type needs to be application/x-amz-json-1.0."""
9341066 service = load_service ("apprunner" )
0 commit comments