AWS SDK v3写入DynamoDB无报错却失败,求排查方案
问题
我正在开发一个AWS Lambda函数,负责将数据写入DynamoDB表,已在SAM模板中配置了相关权限:
- Effect: "Allow" Action: - "dynamodb:GetItem" - "dynamodb:PutItem" - "dynamodb:UpdateItem" - "dynamodb:DeleteItem" Resource: - !Join ["/", [!Sub "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table", '{{resolve:ssm:/examples/example/tableName}}'] ]
调用DynamoDB写入数据的逻辑如下:
dynamoStorage.ts
export const setThings = async (accountId: string, clientKey: string, things: EnhancedSearchFilter[]): Promise<void> => { if (!tableName) { return Promise.reject(new Error(DynamoError.InvalidTableName)); } // 批量写入所有数据到dynamo const promises = things.map((thing) => putThing(accountId, clientKey, thing)); return Promise.allSettled(promises).then((results) => { if (results.some((result) => result.status === 'rejected')) { customLogger.error('Failed to put things', { clientKey, things }); throw new Error('Failed to set all filters'); } }); };
调用DynamoDB的putThing函数
export const putThing = async (accountId: string, clientKey: string, thing: EnhancedThing): Promise<void> => { if (!tableName) { return Promise.reject(new Error(DynamoError.InvalidTableName)); } const thingRef = createThingRef(accountId, thing.id); const params: PutCommandInput = { Item: thingToItem(clientKey, accountId, thing), TableName: tableName }; try { await dynamoClient.send(new PutCommand(params)); return Promise.resolve(); } catch (cause) { customLogger.error('Failed to put thing', { clientKey, thingRef, cause }); throw new Error(`Failed to put thing`, { cause }); } };
在CloudWatch中多次看到上述错误日志,但日志中的cause显示为空对象{}。请问这种场景下我的错误处理是否存在问题?若有该如何改进?若无,为何DynamoDB写入失败却不返回错误信息?
分析与解决方案
错误处理的问题及改进
- 日志序列化导致
cause为空
AWS SDK抛出的DynamoDB错误是自定义类实例,包含大量非枚举属性(如$metadata),而多数日志工具默认只序列化对象的可枚举属性,直接传递原始错误会导致日志中cause显示为空。
改进方法:手动提取错误关键信息,转为可序列化的普通对象:
catch (cause) { const errorDetails = { name: cause.name, message: cause.message, code: cause.code, // 比如ConditionalCheckFailedException、AccessDeniedException等错误码 requestId: cause.$metadata?.requestId, statusCode: cause.$metadata?.httpStatusCode }; customLogger.error('Failed to put thing', { clientKey, thingRef, errorDetails }); throw new Error(`Failed to put thing`, { cause }); }
- 批量写入的错误信息缺失细节
setThings函数仅抛出通用错误,未记录具体失败的项和原因,不利于定位问题。
改进方法:收集失败结果,补充到日志和错误信息中:
return Promise.allSettled(promises).then((results) => { const failedResults = results.filter(r => r.status === 'rejected'); if (failedResults.length > 0) { const failedItems = things.filter((_, idx) => failedResults[idx].status === 'rejected'); const errorMessages = failedResults.map(r => (r as PromiseRejectedResult).reason.message); customLogger.error('Partial failure when putting things', { clientKey, failedItems, errorMessages }); throw new Error(`Failed to set ${failedResults.length} filters: ${errorMessages.join(', ')}`); } });
- 错误传递的完整性优化
虽然使用了{ cause }传递原始错误,但部分日志库或运行环境可能对错误对象处理有限。如果不需要封装错误,可以直接抛出原始错误;若需要封装,可将原始错误的关键信息附加到新错误的属性中。
为什么DynamoDB写入失败却显示空cause
核心原因是错误对象序列化限制:AWS SDK v3的错误对象包含不可枚举属性,默认日志序列化无法识别这些属性,导致日志中cause呈现为空对象。
额外排查点:
- 检查
customLogger配置,是否开启了深度序列化,或者是否有过滤错误属性的规则; - 验证SAM模板中SSM参数解析是否正确,确保资源ARN指向目标DynamoDB表,执行角色权限无遗漏。
内容的提问来源于stack exchange,提问作者Jorge Guerreiro
相关产品推荐
相关产品推荐

