zudo-slack-wisdom
GitHub リポジトリ

検索したい単語を入力

いつでも検索バーを開ける

エラーリファレンス

Lists API 全体にまたがる、カテゴリ駆動で分岐できるエラーコードと、その原因・背景・本番運用ハンドリング方針

概要

slackLists.items.update をはじめとする Lists の他の書き込み・読み取りメソッドは、いずれも失敗時に {"ok": false, "error": "<code>"} を返す。このページは、items.update だけでなくこの節で扱うすべての slackLists.* メソッドにまたがって、ドキュメント化されたエラーコードを原因ごとにまとめる。これにより Worker は、ok でないレスポンスをすべて同じように扱うのではなく body.error で分岐できる。その分岐を実際のリトライ/停止/アラートの方針に落とし込む方法は、後述の「本番運用のエラーハンドリング」を参照。

全一覧

エラー意味
invalid_option_idスラッグが違う — value の代わりにラベルを書き込んだか、キャッシュしたあとでそのオプションがスキーマから削除されたか
invalid_input_typeカラムの型に対して値キーが違うか、配列が必要な場所に裸のスカラーを渡した
invalid_array_arg配列の引数が壊れている — たいていは JSON ではなくフォームエンコードのボディを送っている
invalid_column_id / column_not_found永続化した column_id が古い
invalid_row_id / row_not_found永続化した row_id が古い(items.update から)
record_not_found / record_deleteditems.info における行欠落のスペリング — row_not_found / invalid_row_id と同じ意味だが、メソッドも表記も異なる
duplicated_item_not_founditems.create の複製元の行が見つからない
column_id_not_providedセルに column_id がない(かつ、ドキュメント化されていない column_id_to_create も渡していない)
uneditable_column対象が計算列(created_bylast_edited_bycreated_timelast_edited_time)である
over_cell_fields_limit1 回の呼び出しに含まれるセルが多すぎる(ドキュメント JSON では maxItems: 100
over_row_maximumリストあたりのアイテム数の上限に達した(create 経路。この上限を示す唯一の権威あるシグナル)
list_item_limit_exceeded / list_row_limit_exceeded / too_many_items / too_many_records元調査が挙げた容量エラーの別スペリング。未確認 — 下記のタクソノミーの注記を参照
list_not_foundlist_id が不正 — アクセス失敗の場合にも返る、後述
no_permission / access_denied / permission_deniedbot トークンがこのリストへのアクセス権を持っていない
team_access_not_grantedトークンが必要なワークスペースアクセス権を持っていない — items.update に限らずほとんどの slackLists.* メソッドに現れる
paid_teams_onlyワークスペースが無料プランである — リストは有料プランの機能
lists_disabled_user_team管理者がそのワークスペースでリストを無効化している(上のプランゲートとは別物)
archive_not_supporteditems.list のアーカイブ済みアイテムクエリに関するプラン段階のエラー — 呼び出し元のプランではアーカイブフィルタが使えない
missing_scopeトークンに lists:write スコープがない
not_allowed_token_typeこのメソッドに対してトークンの種類が違う(bot トークンが必要なところにユーザートークンを使った、あるいはその逆)
not_authed / invalid_auth / token_expired / token_revokednot_allowed_token_type と並ぶ、より広いトークン認証系のエラー群 — トークンがない、検証に失敗する、期限切れ、失効済みのいずれか
invalid_blocks / invalid_text_blocktext / notes カラムに対する rich_text セルの形が不正
ratelimitedレート制限に達した — Retry-After ヘッダーに従うこと

select カラムのエラー

invalid_option_id は、select カラムが本番で使われ始めると最も頻繁に目にすることになるエラーだ。ワイヤー上は同じに見える 2 つの異なる状況で発火する:

  • 送った値が value のスラッグではなく ラベル である — ラベルが決して受理されない理由は select カラムを参照。

  • そのオプションは かつて存在していた が、人間が UI でリストのスキーマを編集して削除した — スキーマの可変性を参照。キャッシュしたスラッグのマップはこれが起きたことを知りようがない。このエラーが予期しないものであれば items.info 経由で list_metadata.schema を読み直すこと。

invalid_input_typeinvalid_array_arg はどちらも値のエラーではなく形のエラーだ — 型付きの値キーの一覧と、単一の値であってもほぼすべてが配列で包まれる理由はリストアイテムへの書き込みを参照。

古い ID に起因するエラー

invalid_column_id / column_not_foundinvalid_row_id / row_not_found は、いずれも永続化した ID がもはや解決できないことを意味する。items.info は同じ行欠落の状態を独自のスペリング、record_not_foundrecord_deleted で報告する — 原因は同じでもメソッドと表記が違うため、どちらのメソッドで表面化したかにかかわらず古い row id を捕まえるには、コードマッチングの分岐は両方のファミリーをチェックする必要がある。items.createduplicated_item_not_found は、一段階手前で起きる同じ種類の問題だ — 複製元として指定した行そのものが既にない。

リストの構造を再発見する slackLists.infoslackLists.list も存在せず、「外部キーで行を探す」エンドポイントもないため、古い row id からの唯一の復旧手段は、リストをページネーションで全件読み出し、自分の主キーを格納している場所(たとえばソース行の ID を写しているテキストカラム)からマッピングを再構築することだ。古い column_id は、リストのスキーマが自分の知らないところで変わったことを意味する — items.info 経由で list_metadata.schema を読み直すこと。

権限とアクセスのエラー

list_not_found は多義的だ:汎用的な「list_id が不正」というエラーであると同時に、トークンの保持者が正当なリストへのアクセス権を欠いているときに items.update が返すものでもある — リストが bot のチャンネルへ共有されていたにもかかわらずまさにこれが起きたという、コミュニティの報告(slackapi/deno-slack-sdk#472)がある。list_not_found が常に ID の打ち間違いや削除を意味すると決めつけないこと。アクセスの問題である可能性もある。このエラーを判別しにいく代わりに、bot がリストを作ることでアクセスの問題そのものを回避できる理由は select カラムを参照。

no_permissionaccess_deniedpermission_denied はより直接的なアクセス拒否のファミリーであり、後述のプランゲートやスコープのエラーとは別物だ。team_access_not_granted は名前こそ違うが同じファミリーで、トークンのワークスペースレベルのアクセスがそのリストをカバーしていないとき、items.update に限らずほとんどの slackLists.* メソッドで現れる。

list_not_found は「ID が不正」と「アクセスの問題」のどちらの意味にもなり得て、ワイヤー上ではどちらか判別できないため、下記のカテゴリタクソノミーではこれを独自のカテゴリ access_or_stale_id として扱い、上の古い ID のグループにも、ここのアクセス拒否ファミリーにも押し込めない。

プランとスコープのエラー

ゲートの対象が異なる 4 つのエラーがあり、これらは混同しやすい:

  • paid_teams_only — ワークスペース自体が無料プランである。リストには有料プランが必要だ。

  • lists_disabled_user_team — ワークスペースは有料だが、ワークスペースの管理者がリストをオフにしている。これは課金の状態ではなく管理者トグルであり、Worker のエラーハンドリングの分岐から見ると、明示的に両方をチェックしない限り 2 つのエラーは同じに見えてしまう。

  • archive_not_supporteditems.list のアーカイブ済みアイテムクエリが呼び出し元のプランでは使えない。上の 2 つとは別の、より狭いプランゲートだ。

  • missing_scope — トークン自体に lists:write がない。上のエラーと違い、これはワークスペース管理者やプラン段階が制御する何かではなく、正しいスコープでアプリを再インストールすれば解決する。

リッチテキストのエラー

invalid_blocksinvalid_text_block はどちらも、text / notes カラムが妥当な Block Kit の rich_text 構造以外のものを受け取ったことを意味する — 最もよくあるのはプレーンな文字列で、テキストカラムは書き込み経路でこれを決して受け付けない(リストアイテムへの書き込みを参照)。

レート制限

slackLists.items.updateTier 3(50+ リクエスト/分) に位置し、これはドキュメントと Java SDK の機械可読な rate_limit_tiers.json の両方が示すところで、このメソッドについては 2 つのソースが一致している。ratelimited は再試行までに何秒待つべきかを示す Retry-After ヘッダーを伴う。即座に再試行したり固定間隔で再試行したりせず、これに従うこと。

本番運用のエラーハンドリング — コードではなくカテゴリで分岐する

エラーの文字列そのもので分岐する Worker は、コード 1 つにつき同じ一握りの方針を何度も再導出する羽目になる。すべてのコードをまず小さなカテゴリタクソノミーへマッピングし、リトライ/停止/アラートの方針をその カテゴリ で駆動するほうが堅牢だ — Slack が後から追加する新しいコードも、デフォルト扱いに落ちるのではなく既存のバケットに収まる。

カテゴリコード方針
scopemissing_scope恒久的な設定エラー
authnot_allowed_token_typenot_authedinvalid_authtoken_expiredtoken_revoked恒久的な設定エラー
accessno_permissionaccess_deniedpermission_deniedteam_access_not_granted恒久的な設定エラー
access_or_stale_idlist_not_found恒久的な設定エラー
schemainvalid_option_idinvalid_column_id / column_not_founduneditable_columncolumn_id_not_providedinvalid_input_typeinvalid_array_arginvalid_blocks / invalid_text_block恒久的な設定エラー
planpaid_teams_onlylists_disabled_user_teamarchive_not_supported恒久的な設定エラー
capacityover_row_maximumover_cell_fields_limit、および未確認の list_item_limit_exceeded / list_row_limit_exceeded / too_many_items / too_many_records のスペリング恒久的な設定エラー(リトライではなく上限・設計側の修正が必要 — アイテム上限と自動アーカイブを参照)
stale_idinvalid_row_id / row_not_foundrecord_not_found / record_deletedduplicated_item_not_found照合(reconciliation)に回す
transientinternal_errorfatal_errorservice_unavailablerequest_timeoutバックオフ
rate_limitratelimitedバックオフ

最初の 6 行 — scopeauthaccessaccess_or_stale_idschemaplan — に capacity を加えたものはすべて 恒久的な設定エラー だ。次の試行でリクエストの何かが変わるわけではないので、リトライでは直らない。これらのカテゴリのいずれかのコードを受け取ったら、その List の登録を unhealthy とマークし、そのリストへの同期を止め、アラートを上げること — 人間(あるいはスキーマドリフトの再デプロイ、スキーマの可変性を参照)が何かを変えない限り、同期を安全に再開できない。

transientrate_limit はその逆で、バックオフしてリトライする。ratelimited はどれだけ待つべきかを示す Retry-After ヘッダーを伴うが、汎用のサーバーエラー系(internal_errorfatal_errorservice_unavailablerequest_timeout)にはそれがないので、上限付きの指数バックオフを使うこと。

stale_id はそのどちらでもない — 止めるべき設定の問題でもなければ、ただリトライで押し通せばいいノイズでもない。ローカルに永続化した ID がもう解決しなくなったことを意味しており、これはまさに照合パスが正すべきシグナルだ。同期全体を止めたり同じ古い ID を闇雲にリトライしたりするのではなく、次の照合サイクルにフィードしてマッピングを再構築すること。

ログや応答に出す前にエラーコードをサニタイズする

body.error はこちらが送ったリクエストを反映したレスポンスデータであり、信頼できる enum ではなく攻撃者が影響を与えられるものとして扱うこと — 特にログ行やアラートのペイロード、オペレーターがエスケープなしで見る可能性のある場所へ書き込む前に。ログや応答に出す前に ^[a-z0-9_]{1,80}$ に対して検証し、これに一致しないものは生の文字列をそのまま通すのではなく、汎用の「未知のエラー」ラベルにフォールバックすること。

関連

これらのエラーが適用されるリクエスト/レスポンスの契約はリストアイテムへの書き込みを参照。invalid_option_id の背後にある select の値のルールは select カラムを参照。スキーマ自体が API 由来の変更のほとんどに対して閉じている理由はスキーマの可変性を参照。容量エラー over_row_maximum が何を意味し、通常運用でこれを発火させない方法についてはアイテム上限と自動アーカイブを参照。

Revision History

作成更新