- 「Object does not exist or not authorized」と私が初めて格闘した夜
- 結論チェックリスト|まずこの3つを叩けば原因はほぼ絞れる
- なぜ Object does not exist or not authorized は曖昧に見えるのか
- よくある質問 (FAQ)|Object does not exist or not authorized
- 公式ドキュメントには書いていない Object does not exist or not authorized のハマりポイント
- Object does not exist or not authorized の最短デバッグ手順チェックリスト
- 私のチームで実装している Object does not exist or not authorized の予防策
- 参考リンク
- 関連記事
「Object does not exist or not authorized」と私が初めて格闘した夜
金曜の夜21時、データ基盤チームのSlackに「ダッシュボードが全部真っ白なんですけど…」とBIチームから通知が飛んできました。Tableauから叩いているSnowflakeのテーブルにSELECTすると、返ってきたのは SQL compilation error: Object ‘ANALYTICS.SALES.ORDERS_FACT’ does not exist or not authorized. の一文。検索すると「Snowflake Object does not exist or not authorized」で大量の質問が出てくるあの定番エラーです。私はとっさに「権限剥がれたか」と思ったのですが、結論、これ 9割は純粋な権限不足ではなく、ロール経路かスキーマ参照のミスが原因でした。今日はその切り分け方を、検証SQLと期待出力ベースで全部書きます。
この記事では、Snowflakeの「Object does not exist or not authorized」エラーについて、ロール・USAGE権限・大文字小文字・フルパス指定・DROP済みテーブルの5つを中心に、最短で原因を切り分ける方法を解説します。

結論チェックリスト|まずこの3つを叩けば原因はほぼ絞れる
長文を読む前に、コンソール(Snowsight Worksheet)で次の3クエリを上から順に実行してください。多くの場合、ロール違い・USAGE不足・参照先DB/スキーマ違いのどれかでこのエラーは終わります。
-- 1. 自分が今どのロール・DB・スキーマで動いているか
SELECT CURRENT_ROLE(), CURRENT_DATABASE(), CURRENT_SCHEMA();
-- 2. テーブルをフルパスで叩いてみる (大文字小文字・スキーマ違いを切り分け)
SELECT * FROM DB_NAME.SCHEMA_NAME.TABLE_NAME LIMIT 1;
-- 3. 今のロールに何が付与されているか
SHOW GRANTS TO ROLE <ROLE_NAME>;
1番目の結果が想定外のロール(例: 自動でPUBLICになっている)、2番目でもエラーが出るならフルパスやオブジェクト存在の問題、3番目で対象テーブル/スキーマへのGRANTが見つからなければ権限経路の問題、と一発で当たりが付きます。以降のケース解説は、この3クエリの結果を見ながら読むと10倍効率的です。
なぜ Object does not exist or not authorized は曖昧に見えるのか
Snowflakeはセキュリティ設計上、「存在するが権限がない」と「そもそも存在しない」を区別して教えてくれません。区別したらオブジェクト名から内部構造が漏れるからです。よって 「物理的にオブジェクトが無い」系統(削除済み・スペルミス・別DB/別アカウントにある)と、「現在のロール経路で見えない」系統(USAGE不足、ロール切替忘れ、FUTURE GRANTS漏れ)の2系統を、こちらが能動的に切り分ける必要があります。以降は実務で踏みやすい順に7ケースを並べます。
ケース1: ロールを切り替え忘れている (Object does not exist or not authorized 最頻出)
症状の見分け方: 同僚は見えているのに自分だけ見えない。WorksheetのRoleピッカーが PUBLIC や ACCOUNTADMIN のままになっている。
検証SQL:
SELECT CURRENT_ROLE(), CURRENT_WAREHOUSE(), CURRENT_DATABASE(), CURRENT_SCHEMA();
期待出力(問題があるとき):
+--------------+--------------------+----------------+----------------+
| CURRENT_ROLE | CURRENT_WAREHOUSE | CURRENT_DATABASE| CURRENT_SCHEMA|
|--------------+--------------------+----------------+----------------|
| PUBLIC | NULL | NULL | NULL |
+--------------+--------------------+----------------+----------------+
解決SQL:
USE ROLE ANALYST_ROLE;
USE WAREHOUSE ANALYST_WH;
USE DATABASE ANALYTICS;
USE SCHEMA SALES;
SELECT COUNT(*) FROM ORDERS_FACT;
期待出力:
+----------+
| COUNT(*) |
|----------|
| 124350 |
+----------+
ケース2: 親オブジェクト(DB/スキーマ)へのUSAGE権限がない
症状の見分け方: テーブル単位の SELECT 権限は持っているのに見えない。SHOW TABLES IN SCHEMA ... も空。
検証SQL:
USE ROLE ANALYST_ROLE;
SHOW GRANTS TO ROLE ANALYST_ROLE;
期待出力(USAGEが抜けているとき):
+-------------+-----------+------------+-------------------------+
| privilege | granted_on| name | granted_to / grantee |
|-------------+-----------+------------+-------------------------|
| SELECT | TABLE | ANALYTICS.SALES.ORDERS_FACT | ROLE / ANALYST_ROLE |
+-------------+-----------+------------+-------------------------+
USAGE on DATABASE ANALYTICS と USAGE on SCHEMA ANALYTICS.SALES の行がありません。Snowflakeは親オブジェクトのUSAGEが無いと、子のSELECT権限を持っていても テーブル自体が「存在しない」扱いになります。
解決SQL:
USE ROLE SECURITYADMIN;
GRANT USAGE ON DATABASE ANALYTICS TO ROLE ANALYST_ROLE;
GRANT USAGE ON SCHEMA ANALYTICS.SALES TO ROLE ANALYST_ROLE;
期待出力:
Statement executed successfully.
Statement executed successfully.
ケース3: スキーマ名・テーブル名の大文字小文字とダブルクォート問題
症状の見分け方: GUIから作ったテーブルや、外部ツール(dbt, Fivetran)が作ったテーブルにアクセスすると失敗する。
誤った例 / 正しい例の並置:
-- ❌ 誤った例: 作成時にダブルクォートで小文字保持されているのを大文字で叩いている
SELECT * FROM analytics.sales.orders_fact;
-- → Object 'ANALYTICS.SALES.ORDERS_FACT' does not exist or not authorized.
-- ✅ 正しい例: 実体名通りクォートする
SELECT * FROM "analytics"."sales"."orders_fact";
検証SQL:
SHOW TABLES LIKE '%orders%' IN SCHEMA "analytics"."sales";
期待出力:
+-----------------------------+-----------+--------+
| name | database | schema |
|-----------------------------+-----------+--------|
| orders_fact | analytics | sales |
+-----------------------------+-----------+--------+
大文字小文字を混ぜたい時は、最初から無クォート(=自動で大文字化)で統一する運用が安全です。命名のクセ自体はSnowflake命名規則ベストプラクティス|ウェアハウス・ユーザー・ロールにまとめてあります。
ケース4: 別データベース・別スキーマを参照している (フルパス忘れ)
症状の見分け方: USE DATABASE しているDBと、見たいテーブルが入っているDBが違う。
検証SQL:
SELECT table_catalog, table_schema, table_name
FROM SNOWFLAKE.ACCOUNT_USAGE.TABLES
WHERE table_name = 'ORDERS_FACT'
AND deleted IS NULL;
期待出力:
+----------------+--------------+--------------+
| TABLE_CATALOG | TABLE_SCHEMA | TABLE_NAME |
|----------------+--------------+--------------|
| RAW | LANDING | ORDERS_FACT |
| ANALYTICS | SALES | ORDERS_FACT |
+----------------+--------------+--------------+
同名テーブルが複数のDBに存在しているケースです。USE DATABASE RAW 状態で SELECT * FROM ANALYTICS.SALES.ORDERS_FACT と書けば一発で当てに行けます。
解決SQL(フルパス指定):
SELECT order_id, amount
FROM ANALYTICS.SALES.ORDERS_FACT
LIMIT 5;
期待出力:
+----------+--------+
| ORDER_ID | AMOUNT |
|----------+--------|
| 1001 | 12000 |
| 1002 | 8500 |
| 1003 | 21000 |
| 1004 | 3300 |
| 1005 | 15750 |
+----------+--------+
ケース5: テーブルがすでにDROPされている (Time Travelとの混同)
症状の見分け方: 昨日まで動いていたクエリが急に失敗。QUERY_HISTORY に DROP TABLE が残っている。
検証SQL:
SELECT query_text, user_name, start_time
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE query_text ILIKE '%DROP%ORDERS_FACT%'
AND start_time >= DATEADD(day, -3, CURRENT_TIMESTAMP())
ORDER BY start_time DESC;
期待出力:
+--------------------------------------+-----------+-------------------------+
| QUERY_TEXT | USER_NAME | START_TIME |
|--------------------------------------+-----------+-------------------------|
| DROP TABLE ANALYTICS.SALES.ORDERS_FACT| ETL_USER | 2026-05-08 23:14:02.000 |
+--------------------------------------+-----------+-------------------------+
解決SQL(DATA_RETENTION_TIME_IN_DAYS 内なら復活可):
USE ROLE SYSADMIN;
UNDROP TABLE ANALYTICS.SALES.ORDERS_FACT;
SELECT COUNT(*) FROM ANALYTICS.SALES.ORDERS_FACT;
期待出力:
Table ORDERS_FACT successfully restored.
+----------+
| COUNT(*) |
|----------|
| 124350 |
+----------+
「AT(OFFSET => -3600) で見えるからまだ存在する」と思いがちですが、Time Travel参照は権限的にも別物です。詳細はSnowflakeタイムトラベルでテーブルの過去データを参照する方法に書いています。

ケース6: ビューの参照先テーブルにロールがアクセスできない
症状の見分け方: ビューには SELECT 権限を付けたのに、叩くとエラー。Snowflakeの通常ビューは ビュー所有者ロール(OWNER)が参照元テーブルにアクセスできることが前提で動きます。所有者ロールが参照元テーブルのSELECT権限を持っていないと、利用者ロールに対してビューのSELECTを付与しても、クエリ実行時に内部の参照解決でこのエラーになります。利用者ロールに参照元テーブルのSELECTを直接付ける方法もありますが、基本は「ビュー所有者ロールが参照元にアクセスできるか」を先に確認します。
検証SQL:
SELECT referenced_database, referenced_schema, referenced_object_name, referenced_object_domain
FROM SNOWFLAKE.ACCOUNT_USAGE.OBJECT_DEPENDENCIES
WHERE referencing_object_name = 'V_ORDERS_DAILY';
期待出力:
+---------------------+-------------------+------------------------+--------------------------+
| REFERENCED_DATABASE | REFERENCED_SCHEMA | REFERENCED_OBJECT_NAME | REFERENCED_OBJECT_DOMAIN |
|---------------------+-------------------+------------------------+--------------------------|
| ANALYTICS | SALES | ORDERS_FACT | TABLE |
| ANALYTICS | SALES | DIM_PRODUCT | TABLE |
+---------------------+-------------------+------------------------+--------------------------+
原因切り分けSQL (ビュー所有者ロールに参照元のSELECTがあるかを確認):
-- まず V_ORDERS_DAILY の所有者ロールを確認
SHOW GRANTS ON VIEW ANALYTICS.SALES.V_ORDERS_DAILY;
-- privilege=OWNERSHIP の grantee_name が所有者ロール (ここでは仮に DATA_ENG_ROLE)
-- その所有者ロールが参照元テーブルにSELECTを持っているか確認
SHOW GRANTS TO ROLE DATA_ENG_ROLE;
解決SQL (基本: 所有者ロールに参照元SELECTを付与する):
USE ROLE SECURITYADMIN;
-- ビュー所有者ロールに対して参照元のSELECTを付ける
GRANT SELECT ON TABLE ANALYTICS.SALES.ORDERS_FACT TO ROLE DATA_ENG_ROLE;
GRANT SELECT ON TABLE ANALYTICS.SALES.DIM_PRODUCT TO ROLE DATA_ENG_ROLE;
または利用者ロール側に直接付ける応急処置 (権限設計が崩れやすいので推奨は所有者経由):
USE ROLE SECURITYADMIN;
GRANT SELECT ON TABLE ANALYTICS.SALES.ORDERS_FACT TO ROLE ANALYST_ROLE;
GRANT SELECT ON TABLE ANALYTICS.SALES.DIM_PRODUCT TO ROLE ANALYST_ROLE;
期待出力:
Statement executed successfully.
Statement executed successfully.
権限設計の基本はSnowflake RBAC入門|ロールで権限管理を始めようとSnowflakeカスタムロール作成とGRANT/REVOKE入門を読むと、ここのつまずきがかなり減ります。
ケース7: 共有(Share)経由のオブジェクトにIMPORTED PRIVILEGESを忘れている
症状の見分け方: Snowflakeセキュアデータシェアリングで受け取ったDBが Snowsight には出るのに、SELECTすると Object does not exist or not authorized が出る。
検証SQL:
SHOW DATABASES LIKE 'SHARED_PROVIDER_DB';
SHOW GRANTS ON DATABASE SHARED_PROVIDER_DB;
期待出力:
+--------------------+--------+-----------+
| name | origin | kind |
|--------------------+--------+-----------|
| SHARED_PROVIDER_DB | SHARE | IMPORTED |
+--------------------+--------+-----------+
解決SQL:
USE ROLE ACCOUNTADMIN;
GRANT IMPORTED PRIVILEGES ON DATABASE SHARED_PROVIDER_DB TO ROLE ANALYST_ROLE;
期待出力:
Statement executed successfully.
よくある質問 (FAQ)|Object does not exist or not authorized
FAQ: Object does not exist or not authorized は権限不足ですか?
必ずしも権限不足とは限りません。Snowflakeはセキュリティ上、「権限はないが存在する」と「そもそも存在しない」を同じメッセージに統一しているからです。実際には、ロールの切り替え忘れ、フルパスのDB/スキーマ違い、テーブル名の大文字小文字違い、DROP済みなど、純粋な権限不足ではないケースも半分くらいあります。だからこそ SELECT CURRENT_ROLE() や SHOW GRANTS での切り分けを最初にやる価値があります。
FAQ: SELECT権限があるのに見えないのはなぜですか?
テーブル単体にSELECTを付けても、親オブジェクトであるDBとスキーマにUSAGEがないと参照経路が成立せず Object does not exist or not authorized が返ります。「テーブルSELECT = 読める」ではなく「DB USAGE → スキーマ USAGE → テーブル SELECT」の3段階すべてが必要です。SHOW GRANTS TO ROLE <ROLE>; を実行して USAGE が3段揃っているかを確認してください。
FAQ: SHOW TABLESでは見えるのにSELECTできないのはなぜですか?
SHOW TABLES はスキーマへのUSAGE権限があればテーブルの「名前一覧」までは表示します。一方 SELECT はテーブル本体へのSELECT権限が別途必要です。「リストには出る=読める」ではないので、SHOW GRANTS ON TABLE <table>; で対象テーブルへのSELECTが付いているかを確認します。
FAQ: 大文字小文字の違いでこのエラーになりますか?
はい、ダブルクォートで囲んで小文字のまま作成したオブジェクト(例: "orders_fact")を、ダブルクォートなしで SELECT * FROM orders_fact と叩くと、Snowflakeは大文字 ORDERS_FACT を探しに行って Object does not exist or not authorized を返します。Snowflakeはダブルクォート無しの識別子を内部で大文字に正規化するためです。SHOW TABLES LIKE '%orders%'; で実体名(大文字小文字)を必ず確認してください。
FAQ: ACCOUNTADMINなのに Object does not exist or not authorized が出るのはなぜ?
ACCOUNTADMINでも、共有DBはIMPORTED PRIVILEGESが必要、マネージドアクセススキーマでは所有権がスキーマ側に集中、レプリカDBは読み取り専用でソース側のGRANTが反映されないといった条件で見えなくなります。万能ロールという思い込みが一番のハマりどころです。
FAQ: Snowsightのオブジェクトツリーには出るのにSELECTで失敗するのはなぜ?
Snowsightのツリーは USAGEを持っているDB/スキーマ配下の名前を見せてくれますが、テーブルへのSELECT権限とは別管理です。「名前が見えている=読める」ではない、と覚えておくと混乱しません。
公式ドキュメントには書いていない Object does not exist or not authorized のハマりポイント
FUTURE GRANTSの「未来限定」落とし穴
GRANT SELECT ON FUTURE TABLES IN SCHEMA ... TO ROLE ... は 付与後に作られたテーブルにしか効かない仕様です。設定前から存在するテーブルには無力なので、初回はかならず GRANT SELECT ON ALL TABLES IN SCHEMA ... も併用します。
USE ROLE SECURITYADMIN;
GRANT SELECT ON ALL TABLES IN SCHEMA ANALYTICS.SALES TO ROLE ANALYST_ROLE;
GRANT SELECT ON FUTURE TABLES IN SCHEMA ANALYTICS.SALES TO ROLE ANALYST_ROLE;
レプリカ・セカンダリDBでのロール権限消失
セカンダリDBはプライマリの オブジェクト定義はレプリケートしますが、権限はレプリケート対象を明示しないと飛びません。DR切替えた瞬間にユーザー全員が Object does not exist or not authorized を見る、というのは現場あるあるです。フェイルオーバ前に SHOW GRANTS をセカンダリ側でも必ず取っておきます。
ロール継承(MANAGED ACCESS)のスキーマ
マネージドアクセススキーマ(WITH MANAGED ACCESS)では、テーブル所有者が個別にGRANTできず、スキーマ所有者しかGRANTを発行できません。テーブルを作ったユーザー本人ですら他ロールに権限を渡せず、エラーが頻発します。
Object does not exist or not authorized の最短デバッグ手順チェックリスト
上から順にコマンドを叩いていけば、ほぼ機械的に絞り込めます。
-- ステップ1: 現在の文脈を確認
SELECT CURRENT_ROLE(), CURRENT_WAREHOUSE(), CURRENT_DATABASE(), CURRENT_SCHEMA();
-- ステップ2: フルパスで叩き直す(タイポ・USE違いを排除)
SELECT * FROM ANALYTICS.SALES.ORDERS_FACT LIMIT 1;
-- ステップ3: アカウント全体に物理的に存在するか
SELECT table_catalog, table_schema, table_name, deleted
FROM SNOWFLAKE.ACCOUNT_USAGE.TABLES
WHERE table_name = 'ORDERS_FACT';
-- ステップ4: 現ロールに必要な権限が全て揃っているか
SHOW GRANTS TO ROLE IDENTIFIER(CURRENT_ROLE());
ステップ2でフルパスにした瞬間に通れば USE文の問題。ステップ3でレコードが返らなければ 物理的に存在しない(削除済み or 別アカウント)。ステップ4でUSAGE/SELECTが揃っていなければ 権限の問題。この三択でほぼ決着します。

私のチームで実装している Object does not exist or not authorized の予防策
うちのチームでは、テーブル名は全て大文字無クォート、ロール名はアクセス領域+用途で ANALYST_SALES_RO のような命名規則を強制し、新スキーマ作成時に GRANT USAGE と GRANT SELECT ON ALL/FUTURE TABLES をセットでTerraform化、ユーザーの DEFAULT_ROLE と DEFAULT_WAREHOUSE はユーザー作成時に必ず個別ロールへ紐付け、月次でACCOUNT_USAGE.GRANTS_TO_ROLESを ANALYST_ROLE 単位でスナップショットして差分監査しています。これだけで Object does not exist or not authorized は激減しました。
参考リンク
- アクセス制御の概要 — Snowflake Documentation
- SHOW GRANTS — Snowflake Documentation
- GRANT <privileges> — Snowflake Documentation
- ACCOUNT_USAGE.GRANTS_TO_ROLES — Snowflake Documentation
- データ共有の利用 — Snowflake Documentation
関連記事
- Snowflake RBAC入門|ロールで権限管理を始めよう – 「権限経路で見えていない」状態を根本理解するための前提知識。
- Snowflakeカスタムロール作成とGRANT/REVOKE入門 – GRANTの粒度とFUTURE GRANTSの使いどころが整理されています。
- Snowflake命名規則ベストプラクティス|ウェアハウス・ユーザー・ロール – 大文字小文字問題を発生させない運用ルールの作り方。
- Snowflake監査ログ入門|Account UsageとInformation Schemaの違い – ACCOUNT_USAGEで物理存在や削除履歴を追う時の必読。
- Snowflakeセキュアデータシェアリング入門 – 共有DBでIMPORTED PRIVILEGESが必要になる理由。

