Skip to content

Field notes

Slack API fix guides

Slack answers almost everything with HTTP 200, and puts the failure in the body as ok: false. Code that checks the status code sees success and moves on, so a bot that is not in the channel, or a token missing one scope, looks exactly like a bot that worked. Each note here explains one such problem and gives you a script that finds it through the API.

Read-only tokenPython and Node.jsTests included
Browse all 20 scripts on GitHub Download them all as a zip Field guide PDF (20 fixes, 63 KB) Follow @allanninal Every fix on this page has a tested Python and Node.js script in the repo. Free, and MIT as stated in its README.
Why these scripts never write

A script here holds a token that can post into your workspace and read your conversations. So these read, they tell you exactly what is wrong, and they print the repair: the scope to add, the channel to join, the reinstall URL. You run it.

Slack is unusually good at saying what is missing — a missing_scope error names both what was needed and what was provided — and most of these notes are about reading the answer it already gave you.

Slack

SlackDiagnostic

Slack answers HTTP 200 and puts the failure in the body

Every Slack Web API error arrives as 200 OK with ok: false in the JSON. Clients that check the status code read every failure as a success.

SlackDiagnostic

Not_in_channel: the bot was never invited to the channel

Installing a Slack app joins it to nothing. The token is valid, the channel ID is right, and every call returns 200 with ok: false and not_in_channel.

SlackDiagnostic

Missing_scope tells you the scope needed and the ones you have

Slack names both needed and provided on a missing_scope error, and X-OAuth-Scopes lists the whole grant. Adding the scope is not enough: reinstall.

SlackDiagnostic

Next_cursor is ignored so only the first page is ever seen

A Slack list call returns 100 items and a cursor. Code that reads the array and stops loses the rest silently, with ok: true and no error anywhere.

SlackDiagnostic

The same message posted three times, and the ts says why

Slack has no idempotency key, so every duplicate is a real second call. The gap between the copies names the cause: a double subscription or a retry.

SlackDiagnostic

The bot answers its own messages in an endless loop

message.channels delivers your own posts back to you. Without a bot_id guard the handler replies to its own reply, and history shows the run.

SlackDiagnostic

Files made public with a link that works without a Slack login

files.list reports public_url_shared per file. Where it is true the permalink_public opens for anyone on the internet, with no login and no expiry.

SlackDiagnostic

Conversations.history clamped to 15 objects and 1 per minute

Ask for 200 messages and get 15. Slack clamps conversations.history for apps that are not on the Marketplace, and there is no setting to change.

SlackDiagnostic

Installs keyed on team_id alone collide on Enterprise Grid

On Grid an install is identified by enterprise_id, team_id and is_enterprise_install. A store keyed on team_id alone hands one tenant another's token.

SlackDiagnostic

Files.upload is retired: one probe returns method_deprecated

files.upload was sunset for every app on 12 November 2025. One argument-free read of the method answers method_deprecated and settles it in a second.

SlackDiagnostic

Every Slack profile has a null email and nothing errored

users:read returns profiles with no email at all. The address needs users:read.email, a separate scope, and its absence is a missing key rather than an error.

SlackDiagnostic

Slack disabled event delivery and will not turn it back on

Fail more than 95% of deliveries in an hour and Slack switches your event subscriptions off. Recovery is manual, and the Web API never reports the flag.

SlackDiagnostic

The scope was granted to the user token, not the bot

Slack keeps two scope lists per app. Add the scope to one and call with the other and missing_scope survives every reinstall you throw at it.

SlackDiagnostic

Token_revoked: the app is gone and retrying will not help

token_revoked is permanent. Sweep auth.test across the installation store, sort the dead rows by what should happen to them, and stop scheduling work.

SlackDiagnostic

Account_inactive: the installer left and took the token

A user token dies with its human. Join your install rows against the member directory to find the automations that are one offboarding away from stopping.

SlackDiagnostic

Token_expired every 12 hours because rotation is on

Rotated Slack tokens live 43200 seconds. Read the xoxe. prefix and the stored expires_in to find installs with no refresh loop, before tonight breaks them.

SlackDiagnostic

Slack refresh tokens are single use: a replay kills the pair

Two replicas refreshing a rotating Slack token at once burn a single-use refresh token. The evidence is in your refresh ledger, not in the API.

SlackDiagnostic

Invalid_auth: the xapp- token is in the Web API slot

Slack issues six token classes with different prefixes. A prefix check across your environment finds the swap before a single request is sent.

SlackDiagnostic

Not_allowed_token_type: right secret, wrong token class

The token authenticates everywhere else and one method still refuses it. Probe each method and read an argument error as proof the class was accepted.

SlackDiagnostic

The token holds admin scopes the app has never called

Nothing is failing, which is the problem. Compare X-OAuth-Scopes against the methods your code actually calls and prune what has no call site.

Something not covered here?

These are the ones I keep hitting. If yours is broken in a way none of them describes, tell me on LinkedIn — it is usually how the next note gets written.