Snowflake「Failed to access remote file」エラーの原因と解決方法|S3/Azure/GCS別

Snowflake「Failed to access remote file」エラーの原因と解決方法|S3/Azure/GCS別のサムネイル Snowflake
この記事をシェアする𝕏B!FacebookLINEPocket

このエラー、たいてい原因は3つです

外部ステージからデータを読みに行くSQLを叩いた瞬間、いきなり真っ赤な文字で Failed to access remote file と返ってくる。検索でこの記事に辿り着いた人は、おそらく今まさにその画面の前にいるはずです。

結論から先に書きます。このエラーは、ほぼ次の3パターンに収束します。(1) Snowflake側のIAMロール/サービスプリンシパル/サービスアカウントに、対象バケットへの権限が足りない(2) ステージ定義のURLやプレフィックスが間違っている(3) ファイル自体が消されている、または別リージョンにある。この3つです。クラウド側(AWS / Azure / GCP)の設定を疑う前に、まずは「どこで詰まっているか」を切り分けるのが最短ルートになります。

再現するシチュエーション

典型的なのは、外部ステージに対して LISTCOPY INTO を実行した時です。たとえば、こんなSQLを書いて実行したケース。

-- 外部ステージのファイル一覧を見る
LIST @my_s3_stage;

-- ロードしようとした
COPY INTO sales_raw
FROM @my_s3_stage/2026/05/
FILE_FORMAT = (TYPE = CSV);

すると返ってくるのが、この一文です。

Failure using stage area. Cause: [Failed to access remote file: access denied. 
Please check your credentials]

あるいはGCSなら Failed to access remote file: 403 Forbidden、Azureなら Failed to access remote file: AuthorizationFailure のように、クラウド側のステータスコードがちょこっと顔を出すこともあります。このサフィックスの違いは大事な手がかりなので、エラー全文をコピーしてからウィンドウを閉じる癖をつけておくと良いです。

Snowflakeが外部ステージへアクセスする際にS3・Azure・GCSのSTSやMSI経由で一時トークンを取得し、失敗時にFailed to access remote fileエラーが返る仕組みを示した図解

本当に起きていること

Snowflakeは外部ステージにアクセスする時、内部で「ストレージ統合(Storage Integration)」または「ステージに直書きしたクレデンシャル」を使って、対象クラウドのSTSやMSI経由で一時トークンを取りに行きます。そのトークン取得 or その後のオブジェクト取得のどちらかが失敗した時、Snowflakeは Failed to access remote file という割と雑な一文でまとめて返してきます。

つまり、エラーメッセージを見ただけでは「権限がないのか」「パスが違うのか」「ファイルが存在しないのか」までは分かりません。ここを切り分けるのが第一歩になります。

原因切り分けチェックリスト

順番に潰していくのが近道です。上から順にやれば、だいたい3分くらいで原因が特定できます。

  1. ステージのURLは正しいか: DESC STAGE my_s3_stage; でURLを確認。バケット名のタイポ、末尾スラッシュの抜け落ちは地味によくあります。
  2. クレデンシャル方式の確認: ストレージ統合を使っているのか、ステージにシークレットを直書きしているのか。DESC INTEGRATION で確認。
  3. クラウド側の権限: S3ならIAMロールの信頼関係、AzureならテナントIDの同意、GCSならサービスアカウントへのロール付与。
  4. リージョン: Snowflakeアカウントとバケットのリージョンがクロスリージョンになっていないか。クロスでも動きますが転送料金が乗るので、まずは同リージョンに揃えるのが安全です。
  5. ファイルの存在: 単純に LIST @stage; が空配列を返すなら、パスは合っていてもオブジェクトが消えています。

S3の場合の解決方法

S3で access denied が出る時は、9割がたIAMロールの設定です。Snowflake公式の手順通りに統合を作っても、「あれ?」と詰まるポイントがあります。それが Snowflake側の STORAGE_AWS_IAM_USER_ARNSTORAGE_AWS_EXTERNAL_ID を、AWS側のIAMロールの信頼関係に貼り直す という工程です。

統合を作ると、AWSアカウントIDと外部IDが自動採番されます。これを取り出すには、こうします。

DESC INTEGRATION s3_int;
-- STORAGE_AWS_IAM_USER_ARN と STORAGE_AWS_EXTERNAL_ID の値を控える

ここでハマりがちなのが、統合を作り直すと外部IDがコロッと変わること。一度作って、IAMロールの信頼関係に貼って、テストで失敗したから統合を CREATE OR REPLACE でやり直して……をやると、AWS側に貼ったExternalIDが古いままになり、永遠に Failed to access remote file から抜け出せません。再作成したら必ずもう一度信頼関係を更新する、これは覚えておいて損はありません。

IAMロール本体に付けるポリシーは s3:GetObjects3:GetObjectVersions3:ListBucket あたり。書き込みもするなら s3:PutObjects3:DeleteObject も足します。書き込み権限を忘れると COPY INTO @stage(アンロード)で同じエラーが出るので注意です。

Azure Blob Storageの場合

Azureは少し癖があります。ストレージ統合を作った後、テナントの管理者がAzure Portalで https://login.microsoftonline.com/<tenant_id>/oauth2/authorize?... のURLを開いて、Snowflakeアプリに同意してあげる必要があります。この同意フローを飛ばすと、Snowflake側のSQLエラーは Failed to access remote file、Azure Portalの監査ログには AuthorizationPermissionMismatch が並びます。

同意した後は、対象のストレージアカウントまたはコンテナのIAM(アクセス制御)で、Snowflakeのサービスプリンシパルに 「ストレージ BLOB データ共同作成者」または「ストレージ BLOB データ閲覧者」 ロールを割り当てます。ここで「所有者」を当てがちですが、所有者はデータ平面の権限を持っていないので動きません。意外な落とし穴です。

-- ステージ作成例(Azure)
CREATE STAGE my_az_stage
  URL = 'azure://myaccount.blob.core.windows.net/mycontainer/'
  STORAGE_INTEGRATION = az_int;

GCSの場合

GCSは比較的シンプルです。統合を作ると、Snowflake側でサービスアカウント(xxxxx@gcpuscentral1-1dfa.iam.gserviceaccount.com のような長いやつ)が払い出されるので、これに対してGCSバケットの IAMで Storage Object Viewer(読み込み専用)か Storage Object Admin(読み書き)を付与します。

DESC INTEGRATION gcs_int;
-- STORAGE_GCP_SERVICE_ACCOUNT の値を控えて、GCS側の IAM に貼る

地味にハマりやすいのが、バケットレベルではなくプロジェクトレベルにロールを付けてしまうパターン。プロジェクト全体に権限を撒くのはセキュリティ的にもよろしくないので、必ずバケット単位で絞りましょう。

Snowflakeストレージ統合で払い出されたGCPサービスアカウントに対し、プロジェクト全体ではなくGCSバケット単位でStorage Object ViewerやAdminロールを付与する正しい権限設定範囲を示した図解

切り分けに便利なコマンド

原因がどこにあるか分からない時、まず叩くべきは LIST です。リストが通れば「読み取り権限はOK、ファイルパスが違うだけ」と確定できますし、リストすら通らないなら「権限か接続のレベル」と分かります。

-- 1. ステージ定義の確認
DESC STAGE my_s3_stage;

-- 2. アクセスできるかの最小テスト
LIST @my_s3_stage;

-- 3. それでも分からなければVALIDATE
SELECT SYSTEM$VALIDATE_STORAGE_INTEGRATION(
  's3_int', 's3://mybucket/path/', 'all', true);

SYSTEM$VALIDATE_STORAGE_INTEGRATION は本当に便利な関数で、どこで失敗しているかをJSONで返してくれます。最初に試す価値はあります。なお、エラーメッセージ内のオブジェクト名は大文字に化けて表示されることがあるので、SQLでは小文字で書いているはずなのに「そんなオブジェクト無いよ」と思っても、それはSnowflake側の正規化と覚えておくと混乱しません。

再発防止の運用Tips

同じ罠を踏まないために、現場でSnowflakeを触っていると効いてくるのが次の3つです。

ひとつめは、ストレージ統合は環境(本番/開発)ごとに必ず分けること。同じ統合を共有すると、片方のバケット権限変更がもう片方に波及して事故ります。ふたつめは、ステージ作成後すぐに LIST @stage を流して動作確認をテンプレ化すること。あとからCOPY INTOで気づくより、ステージ単体で潰した方が早いです。みっつめは、クレデンシャル直書きステージを禁止して、統合経由に揃えること。アクセスキー漏洩リスクが減るだけでなく、ローテーション時のメンテも消えます。

COPY INTO周りで他にも引っかかった人は、SnowflakeでCOPY INTOが失敗する原因と解決方法|エラー別チェックリスト に網羅的なチェック項目をまとめてあるので合わせて目を通しておくと安心です。権限まわりで詰まったら Insufficient privileges to operate on の原因と解決手順 もどうぞ。

まとめ

Failed to access remote file は「リモートストレージへのアクセスに失敗した」という汎用エラーで、中身は権限・パス・存在のいずれかです。S3ならExternalID、AzureならテナントConsent、GCSならサービスアカウントへのIAMロール付与、とクラウドごとに勘所が違うのだけは押さえておくと、次に踏んだ時の復旧が一気に速くなるはずです。

参考リンク

関連記事

この記事をシェアする𝕏B!FacebookLINEPocket