使用boto3下载S3文件版本时遭遇NoSuchVersion错误求助
使用boto3下载S3对象版本时出现NoSuchVersion错误
我正尝试使用boto3(版本1.34.113)下载Amazon S3中某文件的所有版本,但持续报错:botocore.exceptions.ClientError: An error occurred (NoSuchVersion) when calling the GetObject operation: The specified version does not exist.
我的Python代码如下:
import boto3 S3_BUCKET = "mybucket" S3_KEY = "mykey" s3_client = boto3.client("s3") paginator = s3_client.get_paginator("list_object_versions") page_iterator = paginator.paginate(Bucket=S3_BUCKET, Prefix=S3_KEY) for page in page_iterator: for version_obj in page.get("Versions", []): version_details = s3_client.get_object( Bucket=S3_BUCKET, Key=S3_KEY, VersionId=version_obj["VersionId"] )
代码能够列出版本,但无法执行get_object操作。
我已进行的排查操作:
- 拥有完整S3访问权限(
s3:*权限作用于*资源) - 本地凭证配置正确
- 可通过AWS控制台S3界面列出并下载版本
- 仅部分文件存在此问题
- S3键并非其他对象的前缀,排除键不匹配问题(list versions使用Prefix,get object使用Key)
- AWS S3 CLI(版本aws-cli/2.15.43 Python/3.11.8 Linux/6.8.0-48-generic exe/x86_64.ubuntu.24 prompt/off)可正常执行
aws s3api list-object-versions --bucket mybucket --prefix mykey和aws s3api get-object --bucket mybucket --key mykey --version-id versionidfromresponseabove outfile命令 - 文件未被删除
- 版本未被删除
解决方案
1. 使用版本对象自带的Key字段
问题大概率是硬编码的S3_KEY和版本对象实际存储的Key存在字符编码或细微差异(比如空格转义、特殊字符处理),直接使用version_obj["Key"]替代硬编码值即可:
import boto3 S3_BUCKET = "mybucket" S3_KEY = "mykey" s3_client = boto3.client("s3") paginator = s3_client.get_paginator("list_object_versions") page_iterator = paginator.paginate(Bucket=S3_BUCKET, Prefix=S3_KEY) for page in page_iterator: for version_obj in page.get("Versions", []): # 使用版本对象自带的Key,避免字符匹配问题 version_details = s3_client.get_object( Bucket=S3_BUCKET, Key=version_obj["Key"], VersionId=version_obj["VersionId"] ) # 可添加保存文件逻辑: # with open(f"{version_obj['Key'].replace('/','_')}_{version_obj['VersionId']}", 'wb') as f: # f.write(version_details['Body'].read())
2. 添加重试机制应对临时不可访问
如果是跨区域复制的版本同步延迟等临时问题,可添加指数退避的重试逻辑:
import boto3 from botocore.exceptions import ClientError import time def get_object_with_retry(s3_client, bucket, key, version_id, retries=3): for attempt in range(retries): try: return s3_client.get_object(Bucket=bucket, Key=key, VersionId=version_id) except ClientError as e: if e.response['Error']['Code'] == 'NoSuchVersion' and attempt < retries - 1: time.sleep(2 ** attempt) # 指数退避等待 continue raise S3_BUCKET = "mybucket" S3_KEY = "mykey" s3_client = boto3.client("s3") paginator = s3_client.get_paginator("list_object_versions") page_iterator = paginator.paginate(Bucket=S3_BUCKET, Prefix=S3_KEY) for page in page_iterator: for version_obj in page.get("Versions", []): version_details = get_object_with_retry( s3_client, S3_BUCKET, version_obj["Key"], version_obj["VersionId"] )
内容的提问来源于stack exchange,提问作者Samkit Jain
相关产品推荐
相关产品推荐

