diff --git a/.changes/next-release/bugfix-s3-1405.json b/.changes/next-release/bugfix-s3-1405.json new file mode 100644 index 0000000000..1cc3d8575a --- /dev/null +++ b/.changes/next-release/bugfix-s3-1405.json @@ -0,0 +1,5 @@ +{ + "type": "bugfix", + "category": "``s3``", + "description": "Fix S3 200 Error handling to address bugs introduced in payload operations." +} diff --git a/botocore/handlers.py b/botocore/handlers.py index 6c68473d4e..d44cb07469 100644 --- a/botocore/handlers.py +++ b/botocore/handlers.py @@ -1245,11 +1245,7 @@ def document_expires_shape(section, event_name, **kwargs): def _handle_200_error(operation_model, response_dict, **kwargs): # S3 can return a 200 response with an error embedded in the body. # Convert the 200 to a 500 for retry resolution in ``_update_status_code``. - if ( - not response_dict - or operation_model.has_streaming_output - or operation_model.has_event_stream_output - ): + if not _should_handle_200_error(operation_model, response_dict): # Operations with streaming response blobs are excluded as they # can't be reliably distinguished from an S3 error. return @@ -1262,6 +1258,22 @@ def _handle_200_error(operation_model, response_dict, **kwargs): ) +def _should_handle_200_error(operation_model, response_dict): + output_shape = operation_model.output_shape + if ( + not response_dict + or operation_model.has_event_stream_output + or not output_shape + ): + return False + payload = output_shape.serialization.get('payload') + if payload is not None: + payload_shape = output_shape.members[payload] + if payload_shape.type_name in ('blob', 'string'): + return False + return True + + def _update_status_code(response, **kwargs): # Update the http_response status code when the parsed response has been # modified in a handler. This enables retries for cases like ``_handle_200_error``.