Snowflake「Object does not exist or not authorized」エラーの原因と解決法|権限・ロール・テーブル参照を確認

Snowflake「Object does not exist or not authorized」エラーの原因と解決法|権限・ロール・テーブル参照を確認 Snowflake
  1. 「Object does not exist or not authorized」と私が初めて格闘した夜
  2. 結論チェックリスト|まずこの3つを叩けば原因はほぼ絞れる
  3. なぜ Object does not exist or not authorized は曖昧に見えるのか
    1. ケース1: ロールを切り替え忘れている (Object does not exist or not authorized 最頻出)
    2. ケース2: 親オブジェクト(DB/スキーマ)へのUSAGE権限がない
    3. ケース3: スキーマ名・テーブル名の大文字小文字とダブルクォート問題
    4. ケース4: 別データベース・別スキーマを参照している (フルパス忘れ)
    5. ケース5: テーブルがすでにDROPされている (Time Travelとの混同)
    6. ケース6: ビューの参照先テーブルにロールがアクセスできない
    7. ケース7: 共有(Share)経由のオブジェクトにIMPORTED PRIVILEGESを忘れている
  4. よくある質問 (FAQ)|Object does not exist or not authorized
    1. FAQ: Object does not exist or not authorized は権限不足ですか?
    2. FAQ: SELECT権限があるのに見えないのはなぜですか?
    3. FAQ: SHOW TABLESでは見えるのにSELECTできないのはなぜですか?
    4. FAQ: 大文字小文字の違いでこのエラーになりますか?
    5. FAQ: ACCOUNTADMINなのに Object does not exist or not authorized が出るのはなぜ?
    6. FAQ: Snowsightのオブジェクトツリーには出るのにSELECTで失敗するのはなぜ?
  5. 公式ドキュメントには書いていない Object does not exist or not authorized のハマりポイント
    1. FUTURE GRANTSの「未来限定」落とし穴
    2. レプリカ・セカンダリDBでのロール権限消失
    3. ロール継承(MANAGED ACCESS)のスキーマ
  6. Object does not exist or not authorized の最短デバッグ手順チェックリスト
  7. 私のチームで実装している Object does not exist or not authorized の予防策
  8. 参考リンク
  9. 関連記事

「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つを中心に、最短で原因を切り分ける方法を解説します。

Snowflake「Object does not exist or not authorized」エラーの原因と解決法|権限・ロール・テーブル参照を確認

結論チェックリスト|まずこの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ピッカーが PUBLICACCOUNTADMIN のままになっている。

検証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 ANALYTICSUSAGE 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_HISTORYDROP 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タイムトラベルでテーブルの過去データを参照する方法に書いています。

テーブルがすでにDROPされている (Time Travelとの混同)の解説図

ケース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 の最短デバッグ手順チェックリストの解説図

私のチームで実装している Object does not exist or not authorized の予防策

うちのチームでは、テーブル名は全て大文字無クォート、ロール名はアクセス領域+用途で ANALYST_SALES_RO のような命名規則を強制し、新スキーマ作成時に GRANT USAGEGRANT SELECT ON ALL/FUTURE TABLES をセットでTerraform化、ユーザーの DEFAULT_ROLEDEFAULT_WAREHOUSE はユーザー作成時に必ず個別ロールへ紐付け、月次でACCOUNT_USAGE.GRANTS_TO_ROLESANALYST_ROLE 単位でスナップショットして差分監査しています。これだけで Object does not exist or not authorized は激減しました。

参考リンク

関連記事