エラーの概要

AWS S3の NoSuchKey エラーは、指定したキー(オブジェクトパス)がバケット内に存在しないことを示すHTTP 404エラーです。このエラーが発生すると、GetObject、HeadObject、DeleteObject などのオブジェクト操作は失敗し、「The specified key does not exist.」というメッセージが返されます。一見すると「オブジェクトがないこと」を示していますが、実際にはキーの指定ミスやプレフィックスの誤り、大文字小文字の区別、削除済みオブジェクトの参照など、複数の原因が絡むことが多いため、正確な診断が重要です。

実際のエラーメッセージ例

{
  "Error": {
    "Code": "NoSuchKey",
    "Message": "The specified key does not exist."
  },
  "ResponseMetadata": {
    "HTTPStatusCode": 404,
    "HTTPHeaders": {
      "content-type": "application/xml"
    }
  }
}

エラーメッセージの読み方:

よくある原因と解決手順

原因1:キー名のスペルミス、パス区切りの誤り

S3のキーは大文字小文字を区別し、ファイルパスの階層は スラッシュ(/ で区切られます。my-file.txtmy_file.txt は異なるキーであり、folder/file.txtfolder\file.txt も区別されます。これらのわずかなスペルミスや区切り文字の誤りが NoSuchKey エラーの最も一般的な原因です。

Before(エラーが起きるコード):

import boto3

s3 = boto3.client('s3')
bucket_name = 'my-bucket'
key = 'documents/my-file.txt'  # キーが実際には 'documents/my_file.txt' で存在する

response = s3.get_object(Bucket=bucket_name, Key=key)
# NoSuchKey エラーが発生

After(修正後):

import boto3

s3 = boto3.client('s3')
bucket_name = 'my-bucket'
key = 'documents/my_file.txt'  # 正しいキー名に修正

response = s3.get_object(Bucket=bucket_name, Key=key)
data = response['Body'].read()
print(f"Successfully retrieved: {key}")

✅ 修正後の確認:

aws s3 ls s3://my-bucket/documents/

my_file.txt が一覧に表示されればキー名が正しいことが確認できます。

原因2:バケット内のオブジェクトの存在確認なしにアクセス

GetObject の前に HeadObject を使って、オブジェクトが実際に存在するか確認していない場合、存在しないキーへのアクセスが直ちに NoSuchKey エラーを引き起こします。特に、ユーザー入力やダイナミックに構築されたキーを使う場合は、事前の存在確認が不可欠です。

Before(エラーが起きるコード):

import boto3

s3 = boto3.client('s3')
bucket_name = 'my-bucket'
user_input_key = 'uploads/user123/profile.jpg'

# オブジェクトの存在を確認せずに直接 GetObject を実行
try:
    response = s3.get_object(Bucket=bucket_name, Key=user_input_key)
except Exception as e:
    print(f"Error: {e}")
    # NoSuchKey エラーが発生する可能性がある

After(修正後):

import boto3
from botocore.exceptions import ClientError

s3 = boto3.client('s3')
bucket_name = 'my-bucket'
user_input_key = 'uploads/user123/profile.jpg'

# HeadObject で存在確認
try:
    s3.head_object(Bucket=bucket_name, Key=user_input_key)
    # オブジェクトが存在する場合のみ GetObject を実行
    response = s3.get_object(Bucket=bucket_name, Key=user_input_key)
    data = response['Body'].read()
    print(f"Successfully retrieved: {user_input_key}")
except ClientError as e:
    if e.response['Error']['Code'] == '404':
        print(f"Object does not exist: {user_input_key}")
    else:
        print(f"Error: {e}")

✅ 修正後の確認:

aws s3api head-object --bucket my-bucket --key "uploads/user123/profile.jpg"

メタデータが表示されれば、オブジェクトが存在することが確認できます。エラーが出た場合は、キー名を見直してください。

原因3:バージョニング有効なバケットで旧バージョンのオブジェクトにアクセス

S3の バージョニング を有効化したバケットでは、オブジェクトが複数のバージョン(VersionId)を持つことがあります。最新バージョンが削除マーカーで標記されている場合、VersionId を明示せずにアクセスすると NoSuchKey エラーが発生します。また、古いバージョンの VersionId を指定しているが、削除されている場合も同じエラーが出ます。

Before(エラーが起きるコード):

import boto3

s3 = boto3.client('s3')
bucket_name = 'versioned-bucket'
key = 'important-file.txt'
old_version_id = '<your-old-version-id>'

# 削除済みまたは無効な VersionId でアクセス
response = s3.get_object(Bucket=bucket_name, Key=key, VersionId=old_version_id)
# NoSuchKey エラーが発生する可能性がある

After(修正後):

import boto3
from botocore.exceptions import ClientError

s3 = boto3.client('s3')
bucket_name = 'versioned-bucket'
key = 'important-file.txt'

# 利用可能なバージョン一覧を取得
versions = s3.list_object_versions(Bucket=bucket_name, Prefix=key)

if 'Versions' in versions:
    # 最新かつ削除されていないバージョンを取得
    for version in versions['Versions']:
        if version['Key'] == key:
            valid_version_id = version['VersionId']
            response = s3.get_object(Bucket=bucket_name, Key=key, VersionId=valid_version_id)
            data = response['Body'].read()
            print(f"Successfully retrieved version: {valid_version_id}")
            break

✅ 修正後の確認:

aws s3api list-object-versions --bucket versioned-bucket --prefix "important-file.txt"

出力された VersionId が有効であることが確認でき、IsLatest: true で最新バージョンを識別できます。

解決策の早見表

解決策実装難易度再起動要否対応OS
キー名のスペルミス・パス区切りを修正不要OS
HeadObject で事前存在確認を追加不要OS
バージョニング有効時に VersionId を指定不要OS

ツール固有の注意点

AWS CLIコマンドラインでの確認方法

S3の操作を AWS CLI で行う場合、aws s3 ls でプレフィックスを指定して存在するオブジェクト一覧を確認することが最初のトラブルシューティングステップになります。

aws s3 ls s3://my-bucket/documents/

このコマンドで期待するキーが表示されない場合、キー名の指定が誤っている、またはオブジェクトが実際に削除済みである可能性が高いです。特に 大文字小文字の区別コマンドラインでは顕著に影響するため、出力結果と照合する際は詳細に比較してください。

IAMアクセス権限による隠蔽

IAM権限が不足している場合、通常は 403 Forbidden が返ります。ただし、オブジェクトが存在せず、かつ s3:ListBucket 権限もない場合は NoSuchKey ではなく 403 が返るため、「存在しないはずのキーで 403 が出る」という逆の混同が生じることがあります。権限関連が疑われる場合は、IAM ポリシーのレビューを並行して行ってください。

CloudFormation・IaC環境での再デプロイ

Infrastructure as Code(CloudFormation、Terraform等)でS3リソースを管理している場合、デプロイ時にキー名の指定が環境変数や出力値と不一致になることがあります。テンプレート内のキー参照がハードコードされていないか、変数展開が正しく実行されているか確認してください。

それでも解決しない場合

ログ確認とデバッグ

AWS CloudTrail で S3 API 呼び出しの詳細ログを確認できます。CloudTrail コンソールから Data events を有効化し、GetObject、HeadObject の呼び出し履歴を確認することで、実際に送信されたキーと受信したレスポンスを追跡できます。

aws cloudtrail lookup-events --lookup-attributes AttributeKey=ResourceName,AttributeValue=my-bucket

バケットポリシー・ACLの確認

aws s3api get-bucket-policy --bucket my-bucket
aws s3api get-object-acl --bucket my-bucket --key "path/to/object"

バケットポリシーによって特定のプリンシパルに GetObject が明示的に拒否されていないか確認してください。

S3 リージョンの確認

aws s3api get-bucket-location --bucket my-bucket

リクエスト送信しているリージョンとバケットの実際のリージョンが異なっていないか確認します。

代替ツールの検討

NoSuchKey エラーが頻発して運用に支障が出る場合は、以下のツールへの移行を検討できます。

  • Google Cloud Storage(GCS) :S3と互換性が高く、オブジェクト存在確認のAPI仕様もシンプルです。特にマルチクラウド戦略がある場合、統一的なSDKで複数クラウドを管理できます。

  • Azure Blob Storage :マイクロソフトエコシステムとの連携が必要な場合に有効です。エラーハンドリングが詳細で、ブロブの存在確認と取得を単一のAPI呼び出しで実行できます。

  • Cloudflare R2 :S3互換のAPIを提供しながら、デフォルトで出力(egress)料金が無料という特性があり、小〜中規模のアプリケーションで NoSuchKey による頻繁な再試行を許容しやすい運用環境を構築できます。

Editor’s Note

Stack Overflow での報告では、「キーは確実に存在しているのに NoSuchKey が出る」というケースが頻繁に報告されており、その多くはキー末尾の改行文字(%0A)や先頭スラッシュなどの特殊文字の混入が原因でした。LocalStack の GitHub Issue #8174 でも、特殊文字(a@a など)を含むフォルダ名で PutObject が NoSuchKey を返す問題が確認されており、特殊文字のエスケープ漏れは見落としやすい点として注意が必要です。現場では、HeadObject での事前確認と S3 サーバーアクセスログ(AWS 公式が直接推奨)の確認から着手するのが有効です。CloudTrail も参照可能ですが、S3 アクセスの直接的な調査には S3 サーバーアクセスログが適しています。

調査について この記事の解決策は、Stack Overflow・GitHub Issues への公開報告を Gemini + Google Search で検索・精査し、実効性の高いものを整理したものです。参照元の URL は Editor’s Note に記載しています。


免責事項:本記事の内容は、執筆時点の公開情報をもとに作成したものです。ソフトウェアの仕様は予告なく変更されることがあります。最新の情報は各ツールの公式サポートページをご確認ください。本記事の情報を利用した結果生じたいかなる損害についても、著者および運営者は責任を負いかねます。