はじめに
2026年9月、Notion はページ書き込み系の API と MCP ツールにおける「タイムアウト時の応答」を変更しました。具体的には、リクエストが期限を超えた場合に返る HTTP ステータスが 500 internal_server_error から 504 gateway_timeout に変わっています。
一見地味な変更に見えますが、「500 を internal error として無条件リトライする」「500 系をまとめて捨てる」といったエラーハンドリングを組んでいる場合、挙動が変わってしまう 重要な変更です。特に Notion を書き込みバックエンドとして使う AI エージェントや、MCP(Model Context Protocol)経由で Notion を操作するツールを開発している方は影響を受けます。
📌 影響を受ける人
- REST API の
Update a page's content as markdownを呼んでいる開発者- MCP ツール
notion-update-page/notion-create-pages/notion-convert-page-to-skillを組み込んだエージェント・ワークフローの開発者- Notion 書き込みに対して自前のリトライ・監視ロジックを実装している人
変更の全体像
今回の変更で、ページ書き込み系の API・MCP ツールがすべて「タイムアウト時は 504」に統一されました。
処理時間の上限そのものを使い切った場合は、これまでどおり 503 service_unavailable が返り、additional_data.retry_guidance にリトライ指針が含まれます。つまり、書き込み系エンドポイントのエラー応答は次の3種類に整理されたことになります。
変更内容
| 項目 | 変更前 | 変更後 |
|---|---|---|
Update a page's content as markdown(REST API) |
タイムアウト時 500 internal_server_error | タイムアウト時 504 gateway_timeout |
notion-update-page(MCP) |
タイムアウト時 500 | タイムアウト時 504 |
notion-create-pages(MCP) |
504(変更なし) | 504 |
notion-convert-page-to-skill(MCP) |
504(変更なし) | 504 |
| 処理時間上限に到達した場合 | 503 + retry_guidance(変更なし) | 503 + retry_guidance |
severity は high の breaking change として扱われています。API のレスポンス自体(ボディの形式やエンドポイントの URL)は変わっていませんが、HTTP ステータスコードという「エラー分岐の入口」が変わる ため、呼び出し側のロジック次第では検知漏れや誤ったリトライを引き起こす可能性があります。
さらに重要な注意点として、Notion は「504 は書き込みが取り消されたことを意味しない」と明言しています。
⚠️ Breaking Change
504 が返ってきても、Notion 側での書き込み処理自体は完了している可能性があります。確認せずに同じリクエストを再送すると、内容の二重書き込み・意図しない上書き が発生するおそれがあります。
影響と対応
対応が必要なのは主に次の3点です。
-
500 のみを判定条件にしているコードを 504 にも対応させる
status === 500のような単一条件でエラー種別を判定している場合、タイムアウトを正しく検知できなくなります。 -
504 受信時は即リトライしない
再試行の前に、対象ページを取得して変更が反映済みかどうかを確認するステップを挟む必要があります。 -
503 とはリトライ方針を分ける
503 はadditional_data.retry_guidanceに従って再試行できますが、504 は「保存確認」が先という点で扱いが異なります。
💡 Tips
監視・アラート設定をしている場合は、「500 系エラー率」のようなアラート条件に 504 を含めているか確認してください。504 を 5xx として一括りに監視していれば問題ありませんが、500 だけをフィルタしている場合はアラートが飛ばなくなる可能性があります。
コード例
Node.js での擬似的なエラーハンドリング例です。Before では 500 のみをタイムアウトとして扱い即リトライしていますが、After では 504/503/500 を明確に区別し、504 では保存確認を挟みます。
Before(変更前を前提にした実装)
async function updatePageWithRetry(pageId, markdown) {
try {
return await notion.updatePageMarkdown(pageId, markdown);
} catch (err) {
if (err.status === 500) {
// タイムアウトのつもりで即リトライしていた
return await notion.updatePageMarkdown(pageId, markdown);
}
throw err;
}
}
After(504/503を踏まえた実装)
async function updatePageWithRetry(pageId, markdown) {
try {
return await notion.updatePageMarkdown(pageId, markdown);
} catch (err) {
if (err.status === 504) {
// 504: 書き込みが取り消されたとは限らないため、
// 再試行の前に現在の状態を確認する
const current = await notion.getPage(pageId);
if (isAlreadyApplied(current, markdown)) {
return current; // 反映済みなら再試行しない
}
return await notion.updatePageMarkdown(pageId, markdown);
}
if (err.status === 503) {
// 503: retry_guidance に従って再試行
const guidance = err.additional_data?.retry_guidance;
if (guidance?.should_retry) {
await sleep(guidance.retry_after_ms ?? 1000);
return await notion.updatePageMarkdown(pageId, markdown);
}
}
throw err;
}
}
MCP ツール経由でエージェントに書き込みを任せている場合も考え方は同じで、notion-update-page / notion-create-pages / notion-convert-page-to-skill の呼び出し結果が 504 だった場合は、エージェントに「保存されたか確認してから再試行するように」という指示・ガードレールを追加しておくと安全です。
まとめ
- Notion のページ書き込み系 API・MCP ツールで、タイムアウト時の応答が 500 → 504 に統一された(severity: high の breaking change)
- 504 は書き込みが取り消されたことを意味しない。再試行前に保存状態の確認が必要
- 処理時間上限を使い切った場合は従来どおり 503 + retry_guidance
- 500 のみを条件にしたエラー判定・監視アラート・リトライロジックがあれば、504 にも対応するよう修正が必要
Notion を書き込みバックエンドとして使うツールやエージェントを運用している場合は、早めにエラーハンドリングのコードを見直しておくことをおすすめします。