AQ Tech Blog

S3へのファイルアクセスで403 Forbiddenが発生した話——Unicode正規化が引き起こした落とし穴

作成者: chorin.sha|2026年06月30日

はじめに

デジタルイノベーション部の謝超倫です。
この記事では、私が最近遭遇した「S3オブジェクトのキー不一致による403 Forbiddenエラー」というエラーについて、 その対応から原因の分析、そして解決にいたるまでの過程を詳しく解説します。
同様のエラーに遭遇した方の問題解決の一助となれば幸いです。

エラーとの遭遇:最初の対応

プロジェクト内で運用している3Dモデルファイルを圧縮するバッチ処理を確認していた際、「ファイルが圧縮されない」問題が発覚しました。
ログを調査したところ、S3からのファイルダウンロード時に以下のエラーが発生していることが判明しました。

Failed to download file: An error occurred (403) when calling the HeadObject operation: Forbidden

最初の対応として、以下を実施しました。

  • エラーメッセージの記録と正確な把握:403エラーはS3オブジェクトのキーが一致しない場合に発生することを確認
  • 発生状況の整理:対象ファイル名は日本語を含む モデル.ifc で、特定の環境でのみ発生
  • 関連情報の収集:ファイルをアップロードした端末のOSを確認(Windows PCと判明)

問題の分析:原因を探る

このエラーの原因を探るために、以下の分析ステップを実施しました。

  • エラーメッセージの詳細な確認と調査:403 ForbiddenはS3のアクセス権限ではなく、オブジェクトキーの不一致が原因の可能性が高いと判断
  • ログファイルの解析:S3に登録されているキーと、バッチ処理がダウンロードしようとしているキーを比較
  • 再現検証:案件メンバーのMac環境ではエラーが再現せず、Windows PCでアップロードしたファイルのみで403エラーが発生することを確認

調査を進める中で、ファイル名に含まれる日本語文字のバイト表現がOS間で異なる可能性に気づきました。

解決へのアプローチ:試行錯誤と検証

原因の仮説を立て、以下の解決策を試みました。

  • 解決策の仮説立てと実行:OSによるUnicode正規化形式の違いを疑い、PythonのunicodedataモジュールでS3キーと取得キーの正規化形式を比較
  • 実行結果の確認と記録:各正規化形式でのバイト列の違いを確認
  • 必要に応じた別のアプローチの検討:正規化統一の実装方針を検討

試したこと1:S3のバケットポリシーやIAM権限の確認 → 結果:権限に問題なし

試したこと2:ファイル名をログ出力してバイト列を比較 → 結果:同じ見た目でもバイト列が異なることを発見

import unicodedata

filename_windows = 'モデル.ifc'  # NFC: モ + デ + ル(単一の「デ」)
filename_mac = 'モテ゛ル.ifc'   # NFD: モ + テ + ゙ + ル(濁点が別文字)

print(list(unicodedata.normalize('NFC', filename_windows)))
# ['モ', 'デ', 'ル', '.', 'i', 'f', 'c']

print(list(unicodedata.normalize('NFD', filename_mac)))
# ['モ', 'テ', '゙', 'ル', '.', 'i', 'f', 'c']

試したこと3:NFD/NFCの違いがS3キーにそのまま保存されているか確認 → 結果:WindowsはNFC、macOSはNFDで保存されていることを特定

最終的な解決策:バッチ処理でファイル名をS3へ登録・検索する際に、NFKCで正規化する処理を追加 → 結果:エラー解消!

import unicodedata

def normalize_filename(filename: str) -> str:
    return unicodedata.normalize('NFKC', filename)

今回の経験から得られたこと

今回のエラーの解決を通して学んだこと、そして今後のために共有したいポイントをまとめます。

  • OSによるUnicode正規化形式の違い(WindowsはNFC、macOSはNFD)が今回の問題を引き起こした。特に日本語の濁点文字(デ、ガ、パ等)は分解されやすく、同じ見た目でもバイト列が異なる
  • トラブルシューティングの際には、「文字化け」だけでなくUnicode正規化形式の不一致という視点も重要である。見た目で気づきにくいのがこの問題の厄介な点
  • 今後、同様のエラーを防ぐためにファイル名をストレージへ保存・取得する際は常にNFKCで正規化する対策を講じたい

Unicode正規化形式の補足

形式 説明
NFD 正準等価性によって分解(Mac標準)
NFC 正準等価性によって分解後、合成(Windows標準)
NFKD 互換等価性によって分解
NFKC 互換等価性によって分解後、合成

まとめ

今回の「S3 403 Forbiddenエラー」の解決事例が、同様の問題に直面している方の参考になれば幸いです。
「文字化け」とは異なりUnicode正規化の不一致は目視では気づきにくいため、 日本語ファイル名を扱うシステムでは正規化の統一を意識することが重要です。

参考

Pythonで文字列をUnicode正規化(unicodedata.normalize)