デジタルイノベーション部の謝超倫です。
この記事では、私が最近遭遇した「S3オブジェクトのキー不一致による403 Forbiddenエラー」というエラーについて、 その対応から原因の分析、そして解決にいたるまでの過程を詳しく解説します。
同様のエラーに遭遇した方の問題解決の一助となれば幸いです。
プロジェクト内で運用している3Dモデルファイルを圧縮するバッチ処理を確認していた際、「ファイルが圧縮されない」問題が発覚しました。
ログを調査したところ、S3からのファイルダウンロード時に以下のエラーが発生していることが判明しました。
Failed to download file: An error occurred (403) when calling the HeadObject operation: Forbidden
最初の対応として、以下を実施しました。
モデル.ifc で、特定の環境でのみ発生このエラーの原因を探るために、以下の分析ステップを実施しました。
調査を進める中で、ファイル名に含まれる日本語文字のバイト表現がOS間で異なる可能性に気づきました。
原因の仮説を立て、以下の解決策を試みました。
試したこと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)
今回のエラーの解決を通して学んだこと、そして今後のために共有したいポイントをまとめます。
| 形式 | 説明 |
|---|---|
| NFD | 正準等価性によって分解(Mac標準) |
| NFC | 正準等価性によって分解後、合成(Windows標準) |
| NFKD | 互換等価性によって分解 |
| NFKC | 互換等価性によって分解後、合成 |
今回の「S3 403 Forbiddenエラー」の解決事例が、同様の問題に直面している方の参考になれば幸いです。
「文字化け」とは異なりUnicode正規化の不一致は目視では気づきにくいため、 日本語ファイル名を扱うシステムでは正規化の統一を意識することが重要です。