-
Notifications
You must be signed in to change notification settings - Fork 553
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DynamoDBDocument can't unmarshall null #3846
Comments
Im not sure what example you used for this. But this looks like a mix of V2 and V3? From what I can see you are trying to:
Put your Item in the DynamoDB table: import { PutCommand, GetCommand } from "@aws-sdk/lib-dynamodb";
import { ddbDocClient } from "./libs/ddbDocClient.js"; // I initialized mine in a spearate file.
const putParams = {
TableName: "TEST_TABLE",
Item: {
Season: 15,
Episode: 301,
Title: {NULL: true},
},
};
const put = async () => {
try {
const data = await ddbDocClient.send(new PutCommand(putParams));
return data;
} catch (err) {
console.error(err);
}
};
put(); Outputs: {
'$metadata': {
httpStatusCode: 200,
requestId: 'REDACTED',
extendedRequestId: undefined,
cfId: undefined,
attempts: 1,
totalRetryDelay: 0
},
Attributes: undefined,
ConsumedCapacity: undefined,
ItemCollectionMetrics: undefined
} To Retrieve your item, instead of using import { PutCommand, GetCommand } from "@aws-sdk/lib-dynamodb";
import { ddbDocClient } from "./libs/ddbDocClient.js";
/*
// Set the parameters
const putParams = {
TableName: "TEST_TABLE",
Item: {
Season: 15,
Episode: 301,
Title: {NULL: true},
},
};
const put = async () => {
try {
const data = await ddbDocClient.send(new PutCommand(putParams));
console.log(data)
return data;
} catch (err) {
console.error(err);
}
};
put();
*/
const getParams = {
TableName: "TEST_TABLE",
Key: {
Season: 15,
Episode: 301,
},
};
const get = async () => {
try {
const response = await ddbDocClient.send(new GetCommand(getParams));
if (!response || !response.Item) {
return null;
} else {
console.log('Code Found:', response.Item);
return response.Item;
}
} catch (err) {
console.error(err);
return null
}
}
get(); Outputs: Code Found: { Season: 15, Title: { NULL: true }, Episode: 301 } |
This issue has not received a response in 1 week. If you still think there is a problem, please leave a comment to avoid the issue from automatically closing. |
@RanVaknin I just hit this error and I am using the V3 of the document client ("3.154.0"). export const getArticleNew = async (articleId: string, language: string): Promise<Record<string, any>> => {
const response = await getDynamoDbDocumentClient().send(
new GetCommand({
Key: {
id: `article:${articleId}`,
sort: `language:${language}`
},
TableName: DYNAMODB_TABLE_NAME
})
)
if (!response || !response.Item) {
Logger.debug('no items')
throw new Error(
`no items found for article "${articleId}" in the "${language}" language`
)
}
return response.Item
} error: TypeError: Cannot read properties of null (reading 'S') after changing the Null field to a string, the code works fine. Failing document item: {
"id": {
"S": "article:2074847"
},
"sort": {
"S": "language:en"
},
"page_image": {
"NULL": true
}
} EDIT:
It appears to start failing with |
@trobert2 Im not sure I understand what seems to be the issue. Are you getting this erron on getCommand or putCommand? Can you add your putCommand code? |
The reason I was asking for your putCommand code is to see how you are storing your items. (I was hoping to see your js putRequest, wasnt sure if you were using the console to store it) Something is indeed odd. I'm able to Put and Get your items without any issue:
const putParams = {
TableName: "trobert2",
Item: {
id: "article:2074847",
sort: "language:en",
page_image: null ,
},
};
const put = async () => {
try {
const data = await ddbDocClient.send(new PutCommand(putParams));
console.log(data)
return data;
} catch (err) {
console.error(err);
}
};
put(); response: {
'$metadata': {
httpStatusCode: 200,
requestId: 'REDACTED',
extendedRequestId: undefined,
cfId: undefined,
attempts: 1,
totalRetryDelay: 0
},
Attributes: undefined,
ConsumedCapacity: undefined,
ItemCollectionMetrics: undefined
} GetItem: const getParams = {
TableName: "trobert2",
Key: {
id: "article:2074847",
sort: "language:en",
},
};
const get = async () => {
try {
const response = await ddbDocClient.send(new GetCommand(getParams));
if (!response || !response.Item) {
return null;
} else {
console.log('Code Found:', response.Item);
return response.Item;
}
} catch (err) {
console.error(err);
return null
}
}
get(); Code Found: { sort: 'language:en', id: 'article:2074847', page_image: null } Maybe I am missing something? Thanks, |
This issue has not received a response in 1 week. If you still think there is a problem, please leave a comment to avoid the issue from automatically closing. |
hello everyone, I'm proposing this be re-opened based on the new information I am about to share. this seems to still be an issue in version @RanVaknin I'm sorry, but I don't really think there was actually new information requested in order to mark the ticket with That being said, I have identified the crux of the problem. It comes from
removing The logger implementation I am using is based on
@vbanderov, would you be so kind to also confirm that you also used a custom logger? I would like to kindly ask for this issue to be re-opened. I think there should either be more information around the logger object that can be passed as configuration or more restrictions should be added to that type to ensure that this functions as it is expected. Thank you and kind regards |
We are experiencing this same issue, using
When I omit the logger option, or specifically the Looking at |
Can confirm this issue. My team and I are getting the same trace using the |
We are also experiencing this issue though only as of 3.209.0, however it does seem to be the same problem that started this thread. The core problem is that DynamoDBDocumentClient does not define its own
but it is getting:
Then when it tries to extract the value here it throws the error because it first tries to access The error only occurs when the value is null because for any other value type, take a string for example:
The reason this has begun happening for certain people after 3.209.0 is because previously if you did not provide a logger, then the logger was set to an empty object. The logger middleware only invokes TLDR: DynamoDBDocumentClient does not define it's own logging filter functions and so it uses those that are defined by DynamoDBClient. Those filter functions effectively unmarshall the records and so they expect the records to be marshalled. The logging middleware which invokes those functions does so AFTER the document client has already unmarshalled the records and so the filter functions try to unmarshall AGAIN causing the error. It seems like the document client needs to define its own filter functions that do not unmarshall the records since they will already be unmarshalled. |
Commenting for visibility. Noticing same issue as recent comments while using latest version of DynamoDBDocumentClient without a logger. |
This issue has occurred since the nooplogger was added. Previously the logger middleware didn't run because logger.info wasn't set, now that it is it crashes. That said the actual bug is when attempting to filter sensitive log information no check for null is in place. This code works with 3.204.0 but crashes in 3.209.0 cat package.json
/tmp/dynamdb-null-issue ᐅ cat package.json
{
"name": "dynamdb-null-issue",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/client-dynamodb": "^3.210.0",
"@aws-sdk/lib-dynamodb": "^3.210.0"
}
}
cat index.mjs
import { DynamoDBClient } from '@aws-sdk/client-dynamodb'
import {
DynamoDBDocumentClient,
GetCommand,
PutCommand
} from '@aws-sdk/lib-dynamodb'
const client = new DynamoDBClient({
endpoint: 'http://localhost:8000',
region: 'us-east-1',
credentials: {
accessKeyId: 'x',
secretAccessKey: 'x'
},
// logger: null
})
const dynamodb = DynamoDBDocumentClient.from(client, {
marshallOptions: {
convertEmptyValues: false,
removeUndefinedValues: true,
convertClassInstanceToMap: false
},
unmarshallOptions: {
wrapNumbers: false
}
})
await dynamodb.send(
new PutCommand({
TableName: 'dynamodbStackTable',
Item: {
pk: 'null-issue',
sk: 'null-issue',
value: 'ok',
null: null
}
})
)
const result = await dynamodb.send(
new GetCommand({
TableName: 'dynamodbStackTable',
Key: {
pk: 'null-issue',
sk: 'null-issue'
}
})
)
console.log('result %s', JSON.stringify(result, null, 2))
/tmp/dynamdb-null-issue ᐅ node index.mjs
/private/tmp/dynamdb-null-issue/node_modules/@aws-sdk/client-dynamodb/dist-cjs/models/models_0.js:1144
if (obj.S !== undefined)
^
TypeError: Cannot read properties of null (reading 'S')
at AttributeValueFilterSensitiveLog (/private/tmp/dynamdb-null-issue/node_modules/@aws-sdk/client-dynamodb/dist-cjs/models/models_0.js:1144:13)
at /private/tmp/dynamdb-null-issue/node_modules/@aws-sdk/client-dynamodb/dist-cjs/models/models_0.js:1250:65
at Array.reduce (<anonymous>)
at GetItemOutputFilterSensitiveLog (/private/tmp/dynamdb-null-issue/node_modules/@aws-sdk/client-dynamodb/dist-cjs/models/models_0.js:1248:40)
at /private/tmp/dynamdb-null-issue/node_modules/@aws-sdk/middleware-logger/dist-cjs/loggerMiddleware.js:16:21
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async file:///private/tmp/dynamdb-null-issue/index.mjs:41:16 /tmp/dynamdb-null-issue ᐅ node index.mjs TypeError: Cannot read properties of null (reading 'S')
|
@JamesKyburz I wouldn't necessarily consider that a fix, but instead just a workaround. Also this is exactly what I said a few comments above. This issue certainly needs re-opened and a proper fix applied since it shouldn't be required to explicitly define a null logger and looking at the code in the clients, it doesn't seem like that is a reliable workaround. Also these workarounds don't help anyone that actually use the logger and can't set it to null. I would work on a PR to fix it but I don't have the time at the moment. I'll work on it in my free time, though I'm not sure when I will be able to finish it. |
I also don't think this is the actual solution, but a dirty workaround. |
Hello! Just adding some info here.
I know it may be a bit confusing, but basically, what my team is doing here is to create a simple class whose methods accept the info as parameters and return a typed output based on the desired TS interface. The point is, we're passing I hope this helps someone to debug this issue or at least as a reference for version 3.212.0. |
@trobert2 @Victor-ARC Not sure if it helps in your cases, but you can also set the logger to an empty object: Since DynamoDBClient and DynamoDBDocumentClient share the same sensitive log filter function, any actual solution would need to either change that function to conditionally unmarshall records, or they should not share that function and DynamoDBDocumentClient should define its own. |
Hi everyone. I apologize for the long wait times. We don't comb through closed issues to see activity on it, the activity here got caught by some automation we had. I'm still not able to reproduce this issue even when specifying a logger: const ddbClient = new DynamoDBClient({
region: "us-east-1",
logger: {debug: (data)=>{console.log(data)}}
}) Can someone please upload a gist or a minimal repo with complete code for me to try and replicate this? Thanks, |
@RanVaknin thanks for taking a look. You should be able to reproduce the issue by:
The error occurs when the following are true:
|
Hi @loganhersh , Thanks for the detailed explanation. Will discuss it with the dev team and will have someone take a look ASAP. Repro Code: import { GetCommand,DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
import { DynamoDBClient } from "@aws-sdk/client-dynamodb"
const ddbClient = new DynamoDBClient({region: "us-east-1"})
const marshallOptions = {
convertEmptyValues: false,
removeUndefinedValues: false,
convertClassInstanceToMap: false,
};
const unmarshallOptions = {
wrapNumbers: false,
};
const translateConfig = { marshallOptions, unmarshallOptions };
const ddbDocClient = DynamoDBDocumentClient.from(ddbClient, translateConfig);
// const putParams = {
// TableName: "trobert2",
// Item: {
// id: "article:2074847",
// sort: "language:en",
// page_image: null ,
// },
// };
// const put = async () => {
// try {
// const data = await ddbDocClient.send(new PutCommand(putParams));
// console.log(data)
// return data;
// } catch (err) {
// console.error(err);
// }
// };
// put();
const getParams = {
TableName: "trobert2",
Key: {
id: "article:2074847",
sort: "language:en",
},
};
const get = async () => {
try {
const response = await ddbDocClient.send(new GetCommand(getParams));
if (!response || !response.Item) {
return null;
} else {
console.log('Code Found:', response.Item);
return response.Item;
}
} catch (err) {
console.error(err);
return null
}
}
get(); Output TypeError: Cannot read properties of null (reading 'S')
at AttributeValueFilterSensitiveLog (/test_folder/3846_dynamo_putItem_null/node_modules/@aws-sdk/client-dynamodb/dist-cjs/models/models_0.js:1144:13)
at /test_folder/3846_dynamo_putItem_null/node_modules/@aws-sdk/client-dynamodb/dist-cjs/models/models_0.js:1230:128
at Array.reduce (<anonymous>)
at GetItemOutputFilterSensitiveLog (/test_folder/3846_dynamo_putItem_null/node_modules/@aws-sdk/client-dynamodb/dist-cjs/models/models_0.js:1230:40)
at /test_folder/3846_dynamo_putItem_null/node_modules/@aws-sdk/middleware-logger/dist-cjs/loggerMiddleware.js:16:21
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async get (/test_folder/3846_dynamo_putItem_null/sample.js:32:22) npm list:
|
actually you cannot. The empty object does not satisfy the interface. Please note the "if you use typescript with strict checks." in my previous comment. |
facing the same issue in the latest "3.216.0". Similar to #4222 |
The fix is in https://github.com/aws/aws-sdk-js-v3/releases/tag/v3.224.0. |
Thanks @RanVaknin and @kuhe! |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread. |
Checkboxes for prior research
Describe the bug
When trying to query for a record containing
null
value throughDynamoDBDocument
an error is thrown:SDK version number
@aws-sdk/client-dynamodb@3.142.0
Which JavaScript Runtime is this issue in?
Node.js
Details of the browser/Node.js/ReactNative version
v16.16.0
Reproduction Steps
Observed Behavior
An uncaught error is thrown:
Expected Behavior
The item is successfully returned by the query command.
Possible Solution
Probably need to check if value is
null
before trying to read property 'S' on it. Not sure where that happens though.Additional Information/Context
No response
The text was updated successfully, but these errors were encountered: