Slack APIのnot_in_channelを解消する|Bot招待とchat:write.publicの条件を分ける

Slackアプリからchat.postMessageを呼び、特定の会話だけでnot_in_channelが返るときは、まずOAuth scope不足と会話への参加不足を分けてください。

AIものさし編集部

Slackアプリからchat.postMessageを呼び、特定の会話だけでnot_in_channelが返るときは、まずOAuth scope不足と会話への参加不足を分けてください。scope不足ならmissing_scope、会話に投稿する主体が未参加ならnot_in_channelなど、API responseのerrorを起点に調べます。公開channelへ未参加のまま投稿する要件がある場合はchat:write.publicを検討できますが、このscopeはprivate channelへのアクセスを与えません。単に権限を増やす前に、投稿先・tokenの種類・channel ID・実際のmembershipを順に確かめるのが安全です。

まず確認する3種類のエラー

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

API error最初に疑う点次に確認すること
missing_scopeAPI methodに必要なscopeがtokenへ許可されていないchat.postMessageに対するchat:write、またpublic未参加投稿を意図する場合のchat:write.public(対応token type: Bot / Legacy Bot)が、使っているtokenに実際に付与されているか。chat:write.publicを使う場合はchat:writeも要求される
not_in_channel投稿する主体が対象会話に参加していないchannel ID、public/private、bot userまたはuser tokenの本人が参加しているか
channel_not_foundchannel値が有効でない、またはアプリから利用できないIDの転記ミス、会話種別、アプリやtokenからの可視性、private channelのmembership

この表は切り分けの入口です。同じエラーでも、workspaceの設定やアプリの種類で追加の制約がありえます。responseのokとerrorを保存し、推測した原因ではなくSlackから返った値を記録してください。HTTP statusだけを見て解釈せず、Web API response bodyのerror codeも確認します。成功時はokがtrueとなり、channelとmessage timestamp(ts)が返るため、成功・失敗の両方でresponse bodyを調査記録へ残せます。

chat:writeとchat:write.publicは役割が違う

chat.postMessageの基本scopeはchat:writeです。bot tokenでもuser tokenでもこのmethodが使う基本scopeとしてSlack API referenceに記載されています。chat:writeがあることは、任意の全channelへ参加せず投稿できることを意味しません。

chat:write.publicは、Slack appが自分の所属していないpublic channelへメッセージを送れるようにする追加scopeです。公式scope reference上の対応token typeはBot / Legacy Botです。Slackはこのscopeを利用する場合もchat:writeを併せて要求するよう説明しています。つまり、公開channelへ投稿する権限を広げるためのscopeであり、chat:writeの代わりではありません。また、private channel、DM、その他の非公開会話に入る権利を与えるscopeでもありません。public channel以外へは、投稿主体に必要な会話のアクセス権・membershipを用意する必要があります。

実装前に次の質問を決めます。

  1. アプリは、どのworkspaceのどの会話へ投稿する必要があるか。

  2. 投稿先はpublic channelかprivate channelか、またはDMか。

  3. 投稿はbot userとして行うのか、user tokenの本人として行うのか。

  4. 「public channelへ未参加でも投稿する」ことが本当に要件か。

  5. 投稿先を限定できるなら、アプリを対象channelへ参加させる運用で満たせないか。

public channel全体へ未参加投稿する必要がなければ、chat:write.publicを追加しない設計をまず検討します。必要なchannelにアプリを招待する、または対象がpublic channelである場合に限りAPIで参加する方法が候補になります。Slack app settingsのガイドは、public channelへ投稿するにはchat:write.publicを求めるか、conversations.joinを使うか、ユーザーにアプリを招待してもらう選択肢を案内しています。組織の管理者ポリシーやアプリの権限設計に合う方法を選び、最小権限にします。

誰のmembershipを確認するか

同じ「Slackアプリ」でも、API callに使ったtokenの主体が異なれば、確認すべき参加状態も異なります。bot tokenで投稿するなら、基本の確認対象はアプリのbot userが対象conversationに参加しているかです。user tokenで投稿するなら、user tokenの本人が会話へアクセスできるかを確認します。アプリをchannelへ招待したつもりでも、別tokenを使っていると、その主体のmembershipとは一致しません。

まずアプリ設定や認可情報でtoken typeを特定し、token値そのものはログやチケットに貼らず、種類と付与scopeだけを確認してください。API responseのauthed_userや返却データで利用主体を確かめられる場合は、その識別情報と対象workspaceを突き合わせます。秘密のtokenをデバッグ出力へ出さないことも必須です。

private channelの場合は特に慎重に扱います。対象channelがprivateであれば、chat:write.publicを付けても投稿権限は得られません。正規の管理者またはメンバーにアプリを招待してもらい、招待後に正しいbot userが参加していることを確認します。プライベートchannelの存在自体がアプリから見えない場合、誤った名前やIDをpublic channelとして再試行しても解決しません。チャンネル名だけで決めず、Cから始まるchannel IDと、その会話の種別を照合します。

API responseを起点にする診断手順

次の順で一回の失敗を再現し、余分な投稿を発生させないよう検証します。

  1. 失敗したリクエストを記録する。 method名、workspace、対象channel ID、token type、使用scope一覧、発生時刻、API responseのok/errorを記録します。Authorization header、token、メッセージ内の個人情報は記録に含めません。

  2. channel IDを確認する。 UI上のchannel名を手入力でAPIへ渡している場合は、意図したchannelのIDと一致するか確認します。移行・削除・改名、別workspaceのIDの取り違えがないか見ます。可能ならSlackが提供する正規のconversation一覧取得手段でIDと会話種別を確認します。

  3. token主体を確認する。 bot tokenかuser tokenか、対象workspaceのどのアプリ・ユーザーに属するものかを特定します。環境変数やsecret managerから読み込む構成でも、値は出力せず、tokenの種類と認可scopeだけを確認します。

  4. scopeを確認する。 chat.postMessageにはchat:writeが必要です。scopeを追加したときは、現在APIで使用中のtokenがその認可を反映しているかを確認します。管理画面にscope名が表示されるだけでは、実際のリクエストが古いtokenを使っていない証明になりません。再認可・再インストールが必要かはSlack appの認可状態に従って管理者が判断します。

  5. membershipを確認する。 bot tokenならbot user、user tokenなら本人が対象conversationに参加しているかを確かめます。public channelで未参加投稿が仕様上必要なときだけchat:write.publicを検討します。private channelでは適切な招待を確認します。

  6. 最小のテストを行う。 運用上許可されたテストchannelで、個人情報や機密情報を含まない短い内容を一回だけ送信します。成功後はresponseのchannelとtsを記録し、Slack上で期待したchannelに一件だけ表示されたことを確認します。この記事の手順だけで実workspaceへテスト投稿してよいという意味ではありません。

  7. 元の失敗条件と比較する。 変更前後でtoken type、scope、channel ID、membershipのどれを変えたかを一つずつ記録します。複数条件を同時に変えると、原因が分からないまま過剰な権限だけが残ることがあります。

症状別の判断

missing_scopeが返る

最初にmethodへ必要なscopeがtokenに認可されているか確認します。chat.postMessageではchat:writeが基本です。public channelへ参加せず投稿する場合はchat:write.publicも必要になりますが、これは要求された用途と会話種別を確認してから追加します。別のAPI response、たとえばnot_in_channelが出ているのにscopeだけを増やすのは、根本原因を外す可能性があります。

public channelでnot_in_channelが返る

対象が本当にpublic channelか、bot/user tokenの主体が参加済みか、channel IDが正しいかを確認します。参加済みであれば、他のアクセス制限やtoken主体の取り違えを調べます。未参加のまま投稿することが必要なら、chat:write.publicが正しいSlack appに対して認可され、そのscopeを含むtokenでリクエストされているかを確認します。必要な権限が付いているのに失敗する場合は、Slackの返却errorと管理者ポリシーを照合し、投稿先や認可状態の問題を切り分けます。

private channelでnot_in_channelが返る

chat:write.publicを追加してもこの問題は解決しません。正しいprivate channelへ正しいbot/user主体を招待して参加させる必要があります。権限や参加操作を自動化する前に、組織のchannel管理者がアプリ招待を許可しているか確認してください。参加後は、channel IDの一致と使用tokenを再確認してからテストします。

channel_not_foundが返る

channel IDが誤っている可能性だけでなく、対象会話にアクセスできないことも調べます。private channelでは、アプリやtokenの主体が参加していないために対象が利用できない場合があります。エラー文字列だけでchannelが存在しないと断定せず、workspace、ID、会話種別、membershipを順番に確認します。

scopeを変える前のチェックリスト

  • エラーコードとresponse本文を保存し、HTTP statusと混同していない。

  • 対象workspace、channel ID、public/private/DMの区別を確認した。

  • 投稿主体がbot userかuser token本人かを特定した。

  • 必要なscopeとtokenに実際に付与されたscopeを比較した。

  • public channelへ未参加投稿する要件を確認した。

  • private channelでchat:write.publicが解決策だと誤認していない。

  • scope追加でアプリ利用者・管理者への影響があるか、承認者を確認した。

  • secret tokenをログ、Docs、issueへ貼っていない。

  • 変更後は許可されたtest channelで一件だけ確認する計画がある。

誤った解決で起きやすいこと

  • chat:write.publicをすべてのnot_in_channelに付ける:private channelには適用されず、不要なpublic-channel権限だけを広げる。

  • channel名を自由入力する:別workspaceや同名channelの混同、存在しない会話への送信につながる。安定したIDを使い、対象を確認する。

  • botを招待したのに動かない:実行時に別workspace・別アプリ・user tokenを使っている可能性が残る。設定画面で見たtokenと実リクエストのtoken typeを照合する。

  • scope一覧にあるから新しい権限が有効だと思う:実際の認可・token更新が済んでいない場合がある。認可状態に従い、必要なら管理者の手順で再認可する。

  • エラーを消すために権限を広く付与する:原因がIDの誤りやmembership不足なら解決せず、アクセス範囲だけを増やす。response codeと投稿先条件を先に確認する。

実装前の判定フロー

  1. errorがmissing_scopeなら、methodに必要なscopeを確認する。

  2. errorがnot_in_channelなら、channel typeとtoken主体のmembershipを確認する。

  3. publicで未参加投稿が必要な場合にだけ、chat:write.publicとchat:writeが認可済みかを確認する。

  4. privateなら、必要な主体を正規手順で招待し、参加を確認する。

  5. channel_not_foundなら、ID、workspace、アクセス可能性を確認する。

  6. 条件を一つずつ直し、許可された場所で安全な1件のテストとreadbackを行う。

  7. 説明できない失敗が残る場合は、追加scopeを付け続けずresponse・時刻・request条件をそろえて管理者またはSlack supportへ相談する。

結論:まずscopeではなくエラーと会話条件を見る

chat:writeはchat.postMessageの基本scope、chat:write.publicはアプリが参加していないpublic channelへの投稿を追加で許可するscopeです。private channelへ投稿するには、対象tokenの主体に適切なmembershipが必要です。not_in_channelを見てすぐ全体権限を追加するのではなく、error、channel ID/type、token主体、membershipの順で確認してください。必要な権限を特定した後も、テストは許可されたchannelで最小限に行い、成功responseのchannelとtsで送信先をreadbackします。

Sources