はじめに:「Stream is stale」って何が起きてるの?
Snowflakeで STREAM(ストリーム) を使ってデータの変更を追いかけていたら、ある日突然こんなエラーに出会ったことはありませんか?
Base table 'MY_DB.PUBLIC.MY_TABLE' dropped, cannot read from stream 'MY_STREAM'
-- もしくは
Stream 'MY_STREAM' is stale. Recreate the stream to resume tracking changes.
「stale」は英語で「古くなった・賞味期限切れ」という意味です。つまりこのエラーは、「あなたのストリームは古くなりすぎて、もう変更データを取得できませんよ」という Snowflake からのメッセージなのです。この記事では、なぜこれが起きるのか、どう直すのかを、わかりやすく解説します。

そもそもSTREAMとは?
STREAMは、テーブルに対して「いつ・どこが・どう変わったか」を記録してくれる 変更データキャプチャ(CDC) の仕組みです。テーブルにINSERT/UPDATE/DELETEが起きると、ストリームがその差分を見えるようにしてくれます。
ポイントは、ストリームは 「オフセット」 という “前回どこまで読んだか” のしおりを内部で持っていることです。このしおりから現在までの差分を返してくれるイメージです。
「Stream is stale」になる本当の原因
ストリームが差分を返すには、ベーステーブルの過去データ(Time Travel領域)が残っている必要があります。ここがポイントです!
原因①:オフセットが保持期間を超えた
ストリームは、消費(クエリ)されないままベーステーブルの DATA_RETENTION_TIME_IN_DAYS(デフォルト1日、最大Enterprise版で90日)を超えてしまうと、過去データを参照できなくなりstaleになります。
正確には、ストリームには STALE_AFTER というタイムスタンプがあり、これを過ぎると古くなります。Time Travelの仕組みと深く関係しているため、Snowflake Time TravelとFail-safe入門|誤操作からデータを守る2層バックアップも合わせて読むと理解が深まりますよ。
原因②:ベーステーブルが削除/再作成された
DROP TABLE → CREATE TABLE や、CREATE OR REPLACE TABLE をすると、テーブルのIDが変わるためストリームは追跡先を失います。
原因③:長期間タスクが止まっていた
ストリームをTASKで定期消費している場合、タスクが SUSPENDED 状態のまま放置されると、その間にオフセットが古くなりstaleになります。タスクが動かないトラブルはSnowflakeタスクが動かない原因と「Task is suspended」エラー解決ガイドを参考にしてみてください。
状態を確認してみよう
まずはストリームが本当にstaleかどうか、Snowsightのワークシートで以下のSQLを実行して確認します。
-- ストリームの詳細を見る
SHOW STREAMS LIKE 'MY_STREAM';
-- もしくは情報スキーマから確認
SELECT name, table_name, stale, stale_after, mode
FROM MY_DB.INFORMATION_SCHEMA.STREAMS
WHERE name = 'MY_STREAM';
STALE 列が TRUE になっていればアウトです。STALE_AFTER 列の時刻も合わせて確認しましょう。

復旧手順:ストリームを再構築する
残念ながら、一度staleになったストリームは元には戻せません。作り直しが基本です。以下の流れで対応しましょう。
-- 1) 既存ストリームを削除
DROP STREAM IF EXISTS MY_DB.PUBLIC.MY_STREAM;
-- 2) 同じ名前で再作成(現時点を起点にする)
CREATE OR REPLACE STREAM MY_DB.PUBLIC.MY_STREAM
ON TABLE MY_DB.PUBLIC.MY_TABLE
APPEND_ONLY = FALSE
SHOW_INITIAL_ROWS = FALSE;
-- 3) 動作確認
SELECT * FROM MY_DB.PUBLIC.MY_STREAM LIMIT 10;
もし 過去にさかのぼって差分を取り直したい 場合は、AT | BEFORE 句でTime Travel時点を指定して作成できます(保持期間内に限ります)。
CREATE OR REPLACE STREAM MY_STREAM
ON TABLE MY_TABLE
AT (OFFSET => -60*60); -- 1時間前を起点に
再発防止のベストプラクティス
- 定期的に消費する:TASKでストリームを毎時/毎日読み取り、オフセットを進める習慣をつけましょう。
- 保持期間を延ばす:重要なテーブルは
ALTER TABLE ... SET DATA_RETENTION_TIME_IN_DAYS = 14;のように余裕を持たせます。 - 監視を入れる:
STALE_AFTERが近づいたらSlack通知するなど、アラート運用が安心です。 - テーブル再作成は要注意:
CREATE OR REPLACE TABLEはストリームを壊します。可能ならALTER TABLEやINSERT OVERWRITEを検討しましょう。
まとめ
「Stream is stale」は怖いエラーに見えますが、要は 「オフセットが古すぎて差分を取れません」 という素直なサインです。原因は保持期間切れ・テーブル再作成・タスク停止のいずれか。落ち着いて状態を確認し、ストリームを作り直してから運用ルールを見直しましょう。これで安心してCDCパイプラインを動かせるようになります!
参考リンク
関連記事
- Snowflakeタスクが動かない原因と「Task is suspended」エラー解決ガイド – ストリーム消費をTASKで自動化する際の落とし穴を解説
- Snowflake「Dynamic table refresh failed」の原因と解決ガイド – 自動化された差分処理のもう一つの選択肢、ダイナミックテーブルのトラブル対応
- Snowflake「Time travel data is not available」エラーの原因と過去データ復元のコツ – ストリームの根幹であるTime Travelの保持期間エラーを学べます
- Snowflake Time TravelとFail-safe入門|誤操作からデータを守る2層バックアップ – 保持期間の仕組みを基礎から理解したい方におすすめ


