このエラーが出るときの原因は、たいてい次の3つに収まります。(1) 保持期間を過ぎてしまった、(2) テーブルがTRUNCATEやCREATE OR REPLACEで作り直されてTime Travelの起点がリセットされた、(3) そもそも対象がトランジェント/一時テーブルでTime Travelがほぼ効かない。検索でここに来た方の9割はどれかに当たるはずです。先に結論を置いたので、自分のケースに近いところから読んでください。
まず再現:こういうSQLでエラーになります
実務でSnowflakeを触っていると、「さっき間違ってUPDATEしちゃった、5分前の状態に戻したい」みたいな場面でTime Travelを使います。書き方はこんな感じです。
-- 10分前の状態を覗く
SELECT *
FROM SALES.PUBLIC.ORDERS
AT(OFFSET => -60*10);
-- あるいは特定のクエリIDの直前に戻す
SELECT *
FROM SALES.PUBLIC.ORDERS
BEFORE(STATEMENT => '01b1f3c4-0000-abcd-...');
ところが、運悪く時間が経ちすぎていたり、テーブルが再作成されていたりすると、Snowsightのワークシートに赤い枠でこう返ってきます。
Time travel data is not available for table ORDERS. The requested time is either beyond the allowed time travel period or before the object creation time.
地味にハマるポイントは、エラー文の中のオブジェクト名は大文字に化けて表示されます。クォートで小文字定義していると「いやそんなテーブル名じゃないんだけど」と一瞬混乱するのですが、Snowflakeの内部では識別子は基本大文字保持なので、これは仕様です。
Snowflakeのデータ保持を時間軸で表現したフラットイラスト。左から「現在」「Time Travel期間(0〜90日)」「Fail-safe期間(7日)」「アクセス不可」の4ブロックを横長の帯グラフで描く。境界に小さな旗アイコン。フラットイラスト、モダンなインフォグラフィック調、配色はセージグリーン(#4a6b53)・クリーム(#f6f3ec)・樹皮テラコッタ(#b8845c)を基調、余白を多めに取りミニマル、文字は最小限、横長16:9の比率。
本当の原因:Time Travelの「起点」と「保持日数」の組み合わせ
Time Travelは、テーブルに対する変更履歴のうち「現在からDATA_RETENTION_TIME_IN_DAYS日以内」かつ「テーブルが存在していた期間内」だけを遡れる仕組みです。エラー文を素直に読むと、要求した時刻が次のどちらかに引っかかったということになります。
- 保持期間より前を遡ろうとした(古すぎる)
- テーブルが作成される前を指定した(新しすぎる、というか起点より前)
この「起点」というのが曲者で、CREATE OR REPLACE TABLEやDROP→再CREATEを打った瞬間にリセットされます。同じ名前のテーブルでも、Snowflakeから見れば別オブジェクトです。普段使いのStandardテーブルなら最大90日(Enterprise以上)まで遡れますが、SQLでうっかりREPLACEを打った瞬間、その90日が0日に戻ります。ここは現場でSELECTを書く人ほど忘れがちです。Time Travelの仕組み自体はSnowflake Time TravelとFail-safe入門|誤操作からデータを守る2層バックアップでも整理しているので、合わせて確認しておくと頭が整理されます。
原因切り分けチェックリスト
手元で順番に確認してみてください。だいたい3クエリ以内で原因が確定するはずです。
① テーブルの保持日数を確認する
SHOW TABLES LIKE 'ORDERS' IN SCHEMA SALES.PUBLIC;
-- retention_time 列を見る
ここが0になっていたら、そもそもTime Travelが無効です。トランジェントテーブルや、明示的に0日設定したテーブルが該当します。1なら24時間しか遡れません。
② テーブルの作成時刻を確認する
SELECT TABLE_NAME, CREATED, LAST_ALTERED
FROM SALES.INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'ORDERS';
このCREATEDが、自分が遡りたい時刻より新しければアウトです。「昨日のデータを戻したいのに、今朝REPLACEしていた」というオチがよくあります。
③ 過去のDDL/DMLを追跡する
SELECT QUERY_TEXT, START_TIME, EXECUTION_STATUS
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE QUERY_TEXT ILIKE '%ORDERS%'
AND START_TIME > DATEADD('day', -2, CURRENT_TIMESTAMP)
ORDER BY START_TIME DESC;
CREATE OR REPLACE や TRUNCATE、DROPがどのタイミングで打たれたかを確認します。ACCOUNT_USAGEは最大3時間ほど反映遅延があるので、直近の操作はINFORMATION_SCHEMA.QUERY_HISTORYのテーブル関数を使うと良いです。詳しい使い分けはSnowflake監査ログ入門|Account UsageとInformation Schemaの違いをやさしく解説にまとめています。

解決方法:パターン別の復元手順
パターンA: 保持期間内だがOFFSET指定が雑だった
「3分前くらい」と思ってOFFSET => -60*3と書いたつもりが、計算ミスで日単位を超えていた、というケース。素直にBEFORE句でクエリIDを指定し直すと確実です。
SELECT *
FROM SALES.PUBLIC.ORDERS
BEFORE(STATEMENT => '01b1...壊した時のクエリID');
パターンB: DROPしたテーブルを戻したい
同じ名前で再作成していなければ、UNDROP一発で戻ります。これがTime Travelで一番気持ち良い瞬間です。
UNDROP TABLE SALES.PUBLIC.ORDERS;
注意点として、すでに同名テーブルをCREATE済みだとエラーになります。先に現行テーブルをリネーム退避してからUNDROPします。
ALTER TABLE SALES.PUBLIC.ORDERS RENAME TO ORDERS_TMP;
UNDROP TABLE SALES.PUBLIC.ORDERS;
パターンC: 過去の状態をクローンで丸ごと復元
UPDATE / DELETE をやらかした場合は、復元元のテーブルをCLONEで作り、差し替えるのが安全です。本番テーブルを直接いじるより事故率が下がります。
CREATE TABLE SALES.PUBLIC.ORDERS_RECOVER
CLONE SALES.PUBLIC.ORDERS
AT(OFFSET => -60*30); -- 30分前
-- 差分を確認してから入れ替え
ALTER TABLE SALES.PUBLIC.ORDERS SWAP WITH SALES.PUBLIC.ORDERS_RECOVER;
パターンD: もう保持期間を過ぎている
残念ですが、Time Travelからは取れません。EditionがEnterprise以上で、データが消えてから7日以内であれば、Fail-safe領域に残っている可能性があります。ただしFail-safeはユーザー操作では戻せず、Snowflakeサポートにケースを起票して取り出してもらう流れです。ストレージ料金は加算されているので、戻せたらラッキーくらいの気持ちで申請します。Fail-safeとストレージ料金の関係はSnowflakeのデータ保持期間とFail-safeでストレージ料金を抑えるコツで詳しく扱っています。
再発防止の運用Tips
同じエラーで二度泣かないために、3つだけ仕込んでおくと違います。
まず、本番テーブルの保持日数は最低でも7日以上に揃えること。デフォルトは1日なので、いつ気付くか分からない事故には心もとないです。
ALTER TABLE SALES.PUBLIC.ORDERS
SET DATA_RETENTION_TIME_IN_DAYS = 14;
次に、CREATE OR REPLACEは本番では禁じ手にすること。dbtなどで自動化していると気軽に打ってしまうのですが、これがTime Travelの起点を毎回リセットします。テーブル再生成時はCREATE OR ALTERやTRUNCATE + INSERT、もしくはSWAPで差し替える運用に寄せると履歴が連続します。
最後に、破壊的SQLを打つ前はクエリIDをコピーしておく癖。Snowsightで実行履歴を開けば取れますが、AUTO_SUSPENDで一度ウェアハウスが落ちた直後やワークシートを開き直した直後はセッションが切れて履歴UIの挙動が一瞬怪しくなることがあります。重要な変更前は、自分でクエリIDをメモするくらいで丁度いいです。権限不足で履歴が見えない場合はObject does not exist or not authorized エラーの正体もチェックしてください。

まとめ
Time travel data is not availableは、Snowflakeが「その時刻のデータは物理的にもう持っていません」と正直に告げているだけのエラーです。慌てる前に、(1)保持日数、(2)テーブル作成時刻、(3)直前のDDL、の3点を順に見れば、原因はほぼ確定します。復元できるならUNDROPかCLONE+SWAP、ダメならFail-safe申請、そしてCREATE OR REPLACEと短い保持日数を見直す。この流れを一度通しておくと、次に同じエラーを踏んだ時の精神的ダメージがだいぶ減ると覚えておいて損はありません。
参考リンク
- Snowflake公式: Time Travelの理解と使用
- Snowflake公式: UNDROP TABLE
- Snowflake公式: AT | BEFORE 構文
- Snowflake公式: Fail-safeの理解と使用
関連記事
- Snowflake Time TravelとFail-safe入門|誤操作からデータを守る2層バックアップ – Time TravelとFail-safeの関係を基礎から整理
- Snowflakeのデータ保持期間とFail-safeでストレージ料金を抑えるコツ – 保持日数とコストのバランス調整
- Object does not exist or not authorized エラーの正体 – 履歴やテーブルが見えない時の権限切り分け
- Snowflake「Warehouse does not exist」エラーの原因と解決法 – 復元クエリ実行時にウェアハウスでハマったら
- Snowflake監査ログ入門|Account UsageとInformation Schemaの違いをやさしく解説 – 過去DDLを追跡するためのログ使い分け

