Notion APIの429・529で処理が止まるとき、Retry-Afterとworkspace共有枠を読む

Notion APIの429が出たら、固定で1秒待つだけの処理を足す前に、応答本文のadditional_data.rate_limit_reasonとRetry-Afterを確認します。

AIものさし編集部

Notion APIの429が出たら、固定で1秒待つだけの処理を足す前に、応答本文のadditional_data.rate_limit_reasonとRetry-Afterを確認します。Notionの公式仕様では、接続ごとの制限に加えて、workspace内の複数接続で共有する制限があり、一部endpointには個別制限もあります。自分のintegrationだけ遅くしてもworkspace共有枠が使い切られていれば429は続きます。

529のservice_overloadもRetry-Afterを尊重して再試行します。一方、public_api_request_blockedの429は待っても解決しないため、リトライを止めてNotion Supportへ相談します。書き込みが503になったときは変更が保存された可能性があるので、同じ更新をそのまま繰り返さず、追加のretry_guidanceと現在のオブジェクトを先に確認してください。

最初に見る応答情報

429や529を一律の「混雑」として扱うと、直す場所を間違えます。API応答で確認する項目は次のとおりです。

表は横にスクロールできます

項目意味実装での対応
HTTP status429、529、503などの大分類codeとmessageを含めて記録し、statusだけで原因を決めない
code例:rate_limited、service_overload429/529の分類に使う
additional_data.rate_limit_reasonどの予算・制限に達したかconnection、workspace、endpoint、blocked等を切り分ける
Retry-After次の試行まで待つ秒数数値を読み、指定時間より前に再送しない
additional_data.retry_after本文にも入る待機秒数ヘッダーを読めないクライアントで利用
additional_data.retry_guidance書き込み503時などの個別指示readback指定があれば同じwriteを再送しない

ログに認証token、Authorizationヘッダー、ページ本文を記録してはいけません。調査に必要なrequest IDやendpoint名も、アクセス制限と保持期間を決めてから保存します。

Notion APIの制限は1種類ではない

Notionの現行公式ドキュメントでは、APIリクエストの制限として「接続ごと」と「workspace共有」の両方が説明されています。一部のendpointにはさらに個別の制限があります。workspaceプランに応じて接続ごとの予算が定められ、現行資料ではBusiness / Enterpriseとそれ以外で異なる値が掲載されています。これは接続単位の説明で、workspace共有枠やendpoint制限まで含めた固定の総リクエスト数ではありません。数値を実装へ固定する前に、公開仕様と応答のreasonを再確認してください。

表は横にスクロールできます

応答のreasonどこで詰まったか取る行動
public_api_request_rate_limitこの接続からの送信が速すぎる同じ接続のqueueを止め、Retry-After経過後に再開
public_api_space_request_rate_limitworkspace内の共有予算他の連携・workerも含めて送信を抑え、指定時間待つ
public_api_endpoint_rate_limit特定endpointの制限そのendpointの処理だけを平準化し、別endpointの処理と分離
public_api_request_blocked接続のAPI利用が制限された自動retryを停止し、Notion Supportへ相談
reasonが未知詳細な制限種別が分からないエラー本文を安全に記録し、Retry-Afterに従い、原因を推測しない

workspace共有枠はconnection単位の制限とは別に適用されます。そのため、あるintegrationの速度が接続ごとの平均値以下でも、同じworkspaceを使う他の接続と合算して共有予算を超えれば制限され得ます。複数のworkerがそれぞれ独自にretryすると、待機終了直後に再び一斉送信する「リトライ嵐」も起きます。処理全体でqueueを共有し、workerごとに独立したretry loopを持たせない設計が有効です。

Retry-Afterを中心にした待機と再開

429または529を受け取った場合、まずRetry-Afterの秒数だけ新規リクエストを抑制し、その後に失敗した要求を再試行します。再び429/529が返ったら、指数的に待機時間を増やし、jitter(小さなランダム時間)を加えて同時再送を避けます。最大試行回数を決め、超えたらエラーを記録して上位処理へ返します。待機時間をコードに固定するのではなく、応答ヘッダーを優先してください。

実装の流れは次のとおりです。

  1. API応答を受けたらHTTP status、code、rate_limit_reasonを読む。

  2. 429/529の場合、Retry-Afterを整数秒として読み取る。ヘッダーがなく、公式SDKまたはアプリの契約にfallbackがある場合だけ、指数backoffを使う。

  3. Retry-Afterより早く再送しない。複数workerでは同一queueまたは共有rate limiterを使う。

  4. 再び制限を受けた場合は、指数backoffとjitterを組み合わせる。

  5. attempt数を上限付きにし、上限到達後は自動再送を終える。

  6. public_api_request_blockedなら待機再送せず、運用者へ通知する。

  7. statusとreasonを集計し、どの接続・workspace・endpointで制限が発生するかを調べる。

疑似コードにすると、分岐の要点は次のようになります。

  • statusが429または529:blocked以外はRetry-Afterを尊重し、上限付きで再試行

  • statusが500、502、503、504:HTTP methodとoperationの冪等性を確認してから検討

  • statusが401:認証の問題としてtokenを確認。即時retryしない

  • statusが403:permission不足かworkspace block limitか、messageを読む

  • その他の400:入力・schemaを修正してから再送。失敗した同じpayloadを繰り返さない

Notionの現行API資料は、429/529のRetry-After待機、再度制限を受けた際の指数backoffとjitter、retry上限を示しています。また、429 blockedはretryで解決しないことも説明しています。固定で「1秒待つ」実装では、workspace枠が長いRetry-Afterを返したときに早すぎる再送になります。

429と529の扱い

429 rate_limitedは、APIのリクエスト制限へ到達した状態です。rate_limit_reasonを使えば、接続単位、workspace共有、endpoint別などを区別できる場合があります。reasonがない、または新しい値で未知の場合、既知reasonへ無理に当てはめず、Retry-Afterを守って再試行し、レスポンスを安全な形で記録します。

529 service_overloadはNotion側が一時的に過負荷である状態として扱われ、公式資料は429と同様にRetry-Afterを尊重するよう案内しています。429と529のどちらでも、無制限に再試行するのではなく、上限に達したら失敗として報告します。全リクエストが429だと誤認して401や400まで繰り返すと、原因を直せないまま負荷だけ増えます。

書き込み503は重複実行に注意

503は、Notionが利用できない場合だけでなく、処理に時間がかかり応答を組み立てられなかった場合にも返ることがあります。公式ドキュメントは、書き込みが保存された後に503となるケースを説明しています。この場合、同じ書き込みをもう一度送ると変更が二重に適用される可能性があります。

503を受けたwriteは、単純なretry対象にしません。応答本文のadditional_data.retry_guidanceを確認します。「保存済みの可能性があるのでオブジェクトを読み直す」と示された場合、対象ページやblockをGETして、意図した値・blockが既に反映されているか確認します。状態を確認できず、操作が重複すると困るなら、再試行を止めて人が判断できるようにします。readbackで変更がないことが分かっても、その操作が冪等か、APIに重複防止の仕組みがあるかを見てから再送します。

GETやDELETEなど冪等な操作と、ページ作成・block追加など再送で二重になる操作を同じretry policyへ入れないでください。書き込み結果が曖昧なときのreadbackも、単に成功/失敗を記録するだけでなく、対象IDと変更内容を照合します。作成APIで応答からresource IDを受け取れなかった場合は、Notionの応答にcommit済みresource IDやchild IDがあるかを確認し、それがあれば取得して状態を確かめます。識別可能なIDを取得できないまま同じ作成を再送するのは避けます。

403・401・400を待機で直そうとしない

401は認証の失敗です。tokenの失効、誤ったtoken、権限scopeを確認します。固定時間待っても認証状態は変わりません。403はアクセス権限不足のほか、workspace block limitを示すことがあります。エラーmessageで原因を区別し、権限変更を無断で行わず、必要な担当者へ最小限の権限を相談します。

400 validation_errorは、payloadやschemaに問題がある場合に返ります。型、必須項目、Notion-Versionなどを確認して要求を修正します。Notionのblock数やrich text長など、request payload側のサイズ・件数制限による400もあり得ます。リクエスト制限の429と混同しないよう、statusだけでなくcodeとmessageを読みます。

よくある実装ミス

固定sleepだけを入れる

固定sleepを全接続・全workspaceの共通解決策にすると、短すぎて429を繰り返すか、長すぎて処理が不必要に遅くなります。Retry-Afterを優先し、fallbackは上限付き指数backoffとjitterにします。

各workerが独自にリトライする

複数workerが同時に429を受けた後、同じ時間に再送すると、同じ予算をまとめて消費します。queueまたは共有rate limiterでリクエストを平準化してください。connectionとworkspaceの両方のbudgetに配慮し、単一workerだけ見て原因を断定しないようにします。

503の書き込みを無条件再送する

応答が503でも更新が保存されている場合があります。まずretry_guidanceを読み、対象オブジェクトの現在値を照合します。追記型の処理は重複しやすいため、同じ内容が存在するか、作成されたchild IDを取得できるかも確認します。

すべてのHTTPエラーをretryする

400の入力不備、401の認証、403の権限、blocked 429は待っても直りません。retry対象、readback対象、運用者対応を別々に定義します。

Retry-Afterをログに残すだけで使わない

待機時間をログへ書いても、実際のworkerが同じタイミングで再送すれば意味がありません。queueの再開時刻を共有し、別プロセスからの新規要求も制御します。

導入前の検証チェックリスト

実際のworkspaceで負荷をかける前に、mock responseやテスト環境を使って各分岐を確認します。APIの上限を確かめるために本番へ大量リクエストを送る必要はありません。

  • 429 public_api_request_rate_limitで、Retry-Afterの時間だけ接続queueが待機する

  • 429 public_api_space_request_rate_limitで、同じworkspaceを使う複数workerが抑制される

  • 429 public_api_endpoint_rate_limitで、該当endpointの処理が平準化される

  • 429 public_api_request_blockedでretryが止まり、運用者へ通知される

  • 529 service_overloadでRetry-After後に上限付きretryを行う

  • 429/529が繰り返された場合、指数backoff、jitter、attempt上限が働く

  • 401/403/400は機械的にretryされず、原因に応じて分岐する

  • write 503でresponse.additional_data.retry_guidanceを読み、指示に従ってreadbackする

  • 503後に同一page/blockが重複作成されない

  • ログにtoken、本文、不要な個人情報が入らない

  • retry上限後は最後のstatus、reason、処理IDを記録し、無限ループにならない

テストでは、単にsleep関数が呼ばれたかではなく、「Retry-Afterより前に次のrequestが送られない」ことを時刻制御したテストで検証します。また、workspace共有制限を模擬するときは複数connectionの予算を同じカウンターに接続します。connectionごとにカウンターを分けたmockだけでは、共有枠の不具合を検出できません。

監視で原因を切り分ける

運用メトリクスは、可能ならconnection、workspace、endpoint、status、rate_limit_reason、待機秒数、attempt数で集計します。workspace IDやユーザー情報の扱いはログ閲覧者と保持期間を定めてから行います。全件のURLやrequest bodyを記録する必要はありません。

429が特定のconnectionに集中するなら、その接続の並列度や送信ペースを見直します。複数connectionで同時に起き、public_api_space_request_rate_limitが出るなら、workspaceを共有する他システムを含む処理量を調べます。endpoint reasonなら、対象APIだけを平準化します。reasonが不明なら、公式の新しいreason一覧を確認し、レポート上はUNKNOWNとして扱います。サービス側の一時障害なら529やRetry-Afterの出方も見ます。

workspaceのプランごとの接続予算は変更される可能性があります。プラン名から自分の実効rate limitを固定で推測せず、開発資料の更新を確認し、実応答のRetry-Afterを優先します。workspace共有制限が別枠である点も忘れないでください。API docsに掲載される「平均リクエスト/秒」の数値を、すべてのエンドポイントで常に許される送信速度と読み替えないようにします。

まとめ:待つだけでなく、どの予算かを特定する

Notion APIの429・529に対しては、Retry-Afterを読み、同じworkspaceやendpointの処理をqueueで調整します。reasonを読める場合はconnection/workspace/endpointを分け、blockedならretryを停止します。529は一時過負荷として待機付きで再試行しますが、429/529とも回数に上限を設けてください。

503のwriteは保存済みの可能性があるので、additional_data.retry_guidanceとreadbackを先に確認します。成功が不確かな書き込みを無条件で繰り返さないことが、重複データを防ぎます。認証・権限・入力エラーは待機retryで解決しません。HTTP statusだけで分岐せず、code、reason、message、Retry-Afterを組み合わせて次の行動を選びます。

Sources

Editorial Notes

Fact status: Notion公式Request Limits / Status Codesを2026-10-15に確認。429 rate_limited、rate_limit_reasonのconnection/workspace/endpoint分類、Retry-After、529 service_overload、429 public_api_request_blocked、retry policy、write 503の保存済み可能性とreadback guidanceを確認。プラン別接続数値は時点変動するため数値表を本文へ固定せず、公式ドキュメント再確認を促す。API実測・本番負荷検証は未実施。Reader Jobはエラー分類と安全なretry/再読込の判断まで完了する。