-
Notifications
You must be signed in to change notification settings - Fork 666
Description
Checkboxes for prior research
- I've gone through Developer Guide and API reference
- I've checked AWS Forums and StackOverflow.
- I've searched for previous similar issues and didn't find any solution.
Describe the bug
The AWS SDK for JavaScript v3 throws a TypeError: Cannot read properties of undefined (reading 'Type') when deserializing SQS error responses that return HTTP 500 with Content-Type: text/xml but an empty or malformed body.
This error occurs during the SDK's internal deserialization process before the error can be caught and processed by application code.
Note: This bug was also present in v3.917.0. Also, see related issue #2861.
Regression Issue
- Select this option if this issue appears to be a regression.
SDK version number
@aws-sdk/client-sqs@3.917.0 ... 3.89.0
Which JavaScript Runtime is this issue in?
Node.js
Details of the browser/Node.js/ReactNative version
v23.9.0
Reproduction Steps
I've a minimal reproduction script that creates a mock SQS server returning the problematic response. The script reproduces the error consistently on v3.989.0. We are using @aws-sdk/client-sqs:"^3.917.0"
Steps to Reproduce:
- Install
@aws-sdk/client-sqs@3.989.0 - Copy the script below with any name eg:
reproduce-sqs-error.mjsand Run script with commandnode reproduce-sqs-error.mjs - Observe the
TypeErrorwhen the SDK attempts to deserialize the 500 error response
NOTE: The attached script reproduce-sqs-error.mjs is majorly AI generated and used only to demonstrate the occurrence of the error. The stack trace attached is not from productions logs. But we are facing same issue in production.
Error popping jobs with message: popJobs() - client.send(ReceiveMessageCommand) error with message:
Cannot read properties of undefined (reading 'Type') Deserialization error: to see the raw response,
inspect the hidden field {error}.$response on this object.
This error happens intermittently when the AWS SQS service returns malformed error responses.
Script
Script with output
/**
* Reproduce the "Cannot read properties of undefined (reading 'Type')" error locally.
*
* This script:
* 1. Starts a tiny HTTP server that mimics a broken SQS endpoint
* (returns HTTP 500 with no proper <Error> XML body)
* 2. Creates an SQS client pointing to that mock server
* 3. Calls ReceiveMessageCommand — which triggers the exact deserialization crash
*
* Usage:
* node tmp/reproduce-sqs-error.mjs
*/
import http from 'node:http';
import {
SQSClient,
ReceiveMessageCommand,
} from '@aws-sdk/client-sqs';
// ─── Step 1: Mock SQS server that returns bad responses ───────────────────────
const PORT = 19324;
const server = http.createServer((req, res) => {
console.log(`\n[Mock SQS] Received request: ${req.method} ${req.url}`);
// Simulate different bad response scenarios. Uncomment the one you want to test:
// Scenario A: HTTP 500 with empty body (most likely cause in prod)
res.writeHead(500, { 'Content-Type': 'text/xml' });
res.end('');
// Scenario B: HTTP 500 with non-XML body (e.g., a load balancer error page)
// res.writeHead(500, { 'Content-Type': 'text/html' });
// res.end('<html><body>Service Unavailable</body></html>');
// Scenario C: HTTP 503 with partial XML (missing <Error> structure)
// res.writeHead(503, { 'Content-Type': 'text/xml' });
// res.end('<?xml version="1.0"?><ErrorResponse><RequestId>test-123</RequestId></ErrorResponse>');
// Scenario D: HTTP 200 with malformed XML (would fail during normal deserialization)
// res.writeHead(200, { 'Content-Type': 'text/xml' });
// res.end('not xml at all');
});
server.listen(PORT, async () => {
console.log(`[Mock SQS] Listening on http://localhost:${PORT}`);
console.log('[Mock SQS] Sending ReceiveMessageCommand...\n');
// ─── Step 2: SQS client pointing to mock server ──────────────────────────
const client = new SQSClient({
region: 'us-east-1',
endpoint: `http://localhost:${PORT}`,
credentials: {
accessKeyId: 'fake',
secretAccessKey: 'fake',
},
// Disable retries so we see the error immediately
maxAttempts: 1,
});
const params = {
MessageSystemAttributeNames: ['ApproximateReceiveCount', 'SentTimestamp'],
MaxNumberOfMessages: 10,
MessageAttributeNames: ['jobName', 'xRequestId', 'xRequestTraceId'],
QueueUrl: `http://localhost:${PORT}/queue/test-queue`,
WaitTimeSeconds: 5,
};
// ─── Step 3: Trigger the error ────────────────────────────────────────────
try {
const command = new ReceiveMessageCommand(params);
const data = await client.send(command);
console.log('Unexpected success:', JSON.stringify(data, null, 2));
} catch (err) {
console.log('='.repeat(70));
console.log('ERROR REPRODUCED!');
console.log('='.repeat(70));
// Actual error message
console.log('\n Actual error message:', err.message);
console.log('\nerr.name:', err.name);
console.log('\nerr.$metadata:', JSON.stringify(err.$metadata, null, 2));
// This is the hidden field the SDK tells you to inspect
// Note: $response contains circular refs, so extract key fields
if (err.$response) {
console.log("hello in here")
console.log('\nerr.$response.statusCode:', err.$response.statusCode);
console.log('err.$response.headers:', JSON.stringify(err.$response.headers, null, 2));
console.log('err.$response.body (type):', typeof err.$response.body);
}
console.log('\nerr.$responseBodyText:', err.$responseBodyText);
// This is what the PR would log:
console.log('\n--- What PR #1759 would log: ---');
const safeResponse = err.$response ? { statusCode: err.$response.statusCode, headers: err.$response.headers } : undefined;
console.log(`popJobs() - client.send(ReceiveMessageCommand) error with message: ${err.message}. Raw http Response: ${JSON.stringify(safeResponse)}. AWS Metadata: ${JSON.stringify(err.$metadata)}`);
} finally {
server.close();
console.log('\n[Mock SQS] Server stopped.');
}
});
/**
* Output:
node reproduce-sqs-error.mjs
[Mock SQS] Listening on http://localhost:19324
[Mock SQS] Sending ReceiveMessageCommand...
[Mock SQS] Received request: POST /
======================================================================
ERROR REPRODUCED!
======================================================================
Actual error message: Cannot read properties of undefined (reading 'Type')
Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.
err.name: TypeError
err.$metadata: {
"httpStatusCode": 500,
"attempts": 1,
"totalRetryDelay": 0
}
hello in here
err.$response.statusCode: 500
err.$response.headers: {
"content-type": "text/xml",
"date": "Fri, 13 Feb 2026 00:50:27 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
}
err.$response.body (type): object
err.$responseBodyText: undefined
popJobs() - client.send(ReceiveMessageCommand) error with message: Cannot read properties of undefined (reading 'Type')
Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.. Raw http Response: {"statusCode":500,"headers":{"content-type":"text/xml","date":"Fri, 13 Feb 2026 00:50:27 GMT","connection":"keep-alive","keep-alive":"timeout=5","transfer-encoding":"chunked"}}. AWS Metadata: {"httpStatusCode":500,"attempts":1,"totalRetryDelay":0}
[Mock SQS] Server stopped.
*/
Observed Behavior
The aws-sdk-v3/client-sqs throws:
TypeError: Cannot read properties of undefined (reading 'Type')
Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.
Commands where the error is seen for SQS:
ReceiveMessageCommandDeleteMessageCommand
Expected Behavior
Should have no Deserialization Error: Cannot read properties of undefined (reading 'Type') error when a error response is received from SQS service.
Possible Solution
Add null-safe property access for both .Code AND .Type in the deserialization logic, similar to what was done in PR #4367.
Additional Information/Context
No response