使用AWS Cognito确认后触发器存储用户名至DynamoDB遇Lambda报错
解决AWS Cognito触发器Lambda写入DynamoDB的主键缺失问题
我来帮你排查这个问题,从报错和代码来看,核心问题是你的Lambda代码获取的username值是undefined,导致写入DynamoDB的Item里没有有效的UserId主键,触发了ValidationException。下面分步骤解决:
1. 修正事件字段的取值逻辑
首先得明确AWS Cognito注册确认(Post Confirmation)触发器的事件结构:
- 实际触发时,用户名的字段是
event.userName(注意首字母大写的N) - 但你用的测试事件写的是
"username":"admin"(小写n),这会导致const username = event.userName取不到值,直接变成undefined
如果是测试阶段,要么修改测试事件的字段名:
{ "userName":"admin", "email":"admin@admin.com", "userId": "AD87S" }
要么在代码里兼容两种写法,避免测试和生产环境的差异:
const username = event.userName || event.username;
2. 优化Lambda Handler的异步写法
你的代码混合了async/await和.then/.catch,容易导致逻辑混乱,而且Cognito触发器不需要返回HTTP响应格式,只要返回event或者null就能让Cognito继续后续流程。优化后的代码:
const AWS = require('aws-sdk'); const dynamodb = new AWS.DynamoDB.DocumentClient({region: 'eu-central-1'}); exports.handler = async (event) => { console.log('Received event:', JSON.stringify(event, null, 2)); // 兼容测试事件和实际Cognito事件的用户名字段 const username = event.userName || event.username; if (!username) { console.error('Username not found in event'); // Cognito触发器必须返回event,否则会判定执行失败 return event; } try { await createMessage(username); console.log('Successfully wrote user data to DynamoDB'); // 返回event让Cognito继续处理流程 return event; } catch (err) { console.error('Error writing to DynamoDB:', err); // 抛出错误让Cognito捕获,或者返回event跳过错误 throw err; } }; function createMessage(username){ const familyid = (new Date()).getTime().toString(36) + Math.random().toString(36).slice(2); const params = { TableName: 'eldertech', Item: { 'UserId' : username, 'message' : familyid } }; return dynamodb.put(params).promise(); }
3. 验证DynamoDB表结构
确保你的eldertech表的主键是UserId(字符串类型),和代码里的字段名完全一致(DynamoDB字段名大小写敏感)。如果表的主键是其他名字(比如userId小写),也会触发这个主键缺失的报错。
4. 检查Lambda的IAM权限
最后确认执行这个Lambda的IAM角色有dynamodb:PutItem权限,虽然当前报错是主键问题,但权限不足也会导致写入失败,这是后续需要排查的次要项。
这样修改后,不管是测试事件还是实际Cognito触发,都能正确获取用户名并写入DynamoDB了。
内容的提问来源于stack exchange,提问作者David F.




