aws-sdk-js icon indicating copy to clipboard operation
aws-sdk-js copied to clipboard

Error is swallowed when MessageDeduplicationId is used in standard queue

Open ReallyNotARussianSpy opened this issue 3 years ago • 1 comments

Describe the bug

When I am sending a message to an SQS Queue that is not a FIFO queue and I use MessageDeduplicationId as one of the params, the error that is returned from AWS is not thrown. I had to do a lot of debugging in order to find out what the actual error was. I put a breakpoint here: https://github.com/aws/aws-sdk-js/blob/878c4d68979d2184a48cd49d1912ecfa7e8713d0/lib/event_listeners.js#L363

And I can see that the response is:

<?xml version=\"1.0\"?>
<SendMessageBatchResponse
	xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\">
	<SendMessageBatchResult>
		<BatchResultErrorEntry>
			<Id>ffffff-ffffff-ffffff-ffffff</Id>
			<Code>InvalidParameterValue</Code>
			<Message>The request include parameter that is not valid for this queue type</Message>
			<SenderFault>true</SenderFault>
		</BatchResultErrorEntry>
	</SendMessageBatchResult>
	<ResponseMetadata>
		<RequestId>ffffff-ffffff-ffffff-ffffff-ffffff</RequestId>
	</ResponseMetadata>
</SendMessageBatchResponse>"

But an error was never thrown, when using .promise() or listening on a callback.

Expected Behavior

An error would be thrown when an error is encountered

Current Behavior

The error is swallowed and never propagates outside of the AWS SDK

Reproduction Steps

const params = {
  QueueUrl: "https://sqs.us-east-2.amazonaws.com/FFFFFFFFFF/SomeQueue",
  Entries: [
    {
      Id: "FFFFFFFFFF-FFFFFFFFFF-FFFFFFFFFF",
      MessageBody: "Some Message",
      MessageAttributes: {
        EnvironmentId: {
          DataType: "String",
          StringValue: "dev",
        },
      },
      MessageDeduplicationId: "FFFFFFFFFF",
    },
  ],
};

const sqs = new AWS.SQS({ region: 'us-east-2' });
try {
    await sqs.sendMessageBatch(params).promise();
} catch (err) {
    console.log('this is never triggered');
}

sqs.sendMessageBatch(params, (err, data) => {
    console.log('This is never triggered either');
});

Possible Solution

No response

Additional Information/Context

No response

SDK version used

2.1222.0

Environment details (OS name and version, etc.)

MacOS, Node v14.18.0

ReallyNotARussianSpy avatar Sep 22 '22 20:09 ReallyNotARussianSpy

Hi there - apologies for the long delay response.

The sendMessageBatch operation in SQS can return a partial success response. This means that even if some messages in the batch fail, the operation will still return a response with the successful message IDs and error details for the failed messages. However, SDK doesn't consider this a complete failure and hence, it doesn't throw an error in the promise or callback.

To handle this scenario, you need to check the response data for any error entries and handle them accordingly. Here's how you can modify your code:

const params = {
  QueueUrl: "https://sqs.us-east-2.amazonaws.com/FFFFFFFFFF/SomeQueue",
  Entries: [
    {
      Id: "FFFFFFFFFF-FFFFFFFFFF-FFFFFFFFFF",
      MessageBody: "Some Message",
      MessageAttributes: {
        EnvironmentId: {
          DataType: "String",
          StringValue: "dev",
        },
      },
      MessageDeduplicationId: "FFFFFFFFFF",
    },
  ],
};

const sqs = new AWS.SQS({ region: 'us-east-2' });

// Using promise
sqs.sendMessageBatch(params).promise()
  .then((data) => {
    const errorEntries = data.Failed;
    if (errorEntries && errorEntries.length > 0) {
      const errors = errorEntries.map(entry => `Id: ${entry.Id}, Code: ${entry.Code}, Message: ${entry.Message}`);
      throw new Error(`Errors occurred while sending messages: ${errors.join(', ')}`);
    }
    console.log('Messages sent successfully');
  })
  .catch(err => {
    console.error('Error:', err);
  });

// Using callback
sqs.sendMessageBatch(params, (err, data) => {
  if (err) {
    console.error('Error:', err);
  } else {
    const errorEntries = data.Failed;
    if (errorEntries && errorEntries.length > 0) {
      const errors = errorEntries.map(entry => `Id: ${entry.Id}, Code: ${entry.Code}, Message: ${entry.Message}`);
      console.error(`Errors occurred while sending messages: ${errors.join(', ')}`);
    } else {
      console.log('Messages sent successfully');
    }
  }
});

In this modified code, we're checking the Failed property of the response data. If there are any failed messages, we're constructing an error message with the details of the failed messages and throwing a new Error in the promise chain or logging the error message in the callback.

By handling the errors this way, you'll be able to catch and handle the errors properly when using the sendMessageBatch operation with a non-FIFO queue and providing the MessageDeduplicationId parameter.

Hope that helps, John

aBurmeseDev avatar Aug 27 '24 06:08 aBurmeseDev