SQS触发Lambda调用AWS Transcribe时出现KeyError: 's3'问题排查
根因确认
你的推测完全成立。Lambda直接绑定SQS作为触发源时,事件结构中不存在原生的s3字段,原代码直接按照S3触发Lambda的事件结构取值,必然触发KeyError: 's3'。
现存代码的其他隐性问题
除了事件结构不匹配的核心问题,原代码还存在4处会导致后续执行报错的缺陷:
- 未初始化
transcribe客户端,代码运行到调用转录接口的位置会直接抛出NameError - 拼接的
MediaFileUri格式非法,错误混入了s3://前缀,生成的地址为https://s3-eu-west-2.amazonaws.com/s3://{bucket}/{key},无法被Transcribe服务识别 - 转录任务名写死为固定值,第二次触发时会因为任务名重复创建失败
- 未对S3通知中带URL编码的对象键做解码处理,遇到带特殊字符的MP3文件会直接报文件不存在错误
适配现有架构的修复方案
因为现有架构是S3→SQS→Lambda的固定链路,不需要调整架构,只需要适配SQS投递的事件结构即可:
- 每一条SQS投递到Lambda的record,完整的S3上传通知JSON是以字符串形式存在
record['body']字段中的,需要先通过json解析还原成结构化的事件对象,再从中提取桶名和对象键 - 修正S3文件URI的拼接逻辑,去掉多余的
s3://前缀 - 补全boto3客户端初始化,使用Lambda请求ID生成唯一的转录任务名,避免重名报错
修复后可运行的代码
import boto3 import json import urllib.parse # 初始化依赖的boto3资源和客户端 s3 = boto3.resource('s3') transcribe = boto3.client('transcribe', region_name='eu-west-2') def lambda_handler(event, context): for record in event['Records']: # 解析SQS消息体中的S3上传通知 s3_notification = json.loads(record['body']) # 从解析后的通知中提取S3文件信息 bucket = s3_notification['Records'][0]['s3']['bucket']['name'] encoded_key = s3_notification['Records'][0]['s3']['object']['key'] # 解码URL编码的对象键,兼容带特殊字符的文件 file_key = urllib.parse.unquote_plus(encoded_key) # 生成唯一任务名 job_name = context.aws_request_id # 拼接合法的S3媒体文件URI media_uri = f'https://s3-eu-west-2.amazonaws.com/{bucket}/{file_key}' transcribe.start_transcription_job( TranscriptionJobName=job_name, LanguageCode='en-GB', MediaFormat='mp3', Media={ 'MediaFileUri': media_uri }, OutputBucketName='你配置的实际输出桶名称' )
配置校验注意事项
- 确认Lambda执行角色的权限包含:目标S3桶的
s3:GetObject权限、Transcribe服务的transcribe:StartTranscriptionJob权限、输出桶的s3:PutObject权限 - 确认SQS通知配置的目标队列和Lambda触发配置匹配,没有额外的消息格式转换规则
- 确认Transcribe服务和S3桶处于同一区域,避免跨区域访问失败
内容的提问来源于stack exchange,提问作者CycleNew
相关产品推荐
相关产品推荐

