Slack error channel_not_found: Value passed for channel was invalid
Last verified against Slack API reference - chat.postMessage errors
Value passed for channel was invalid.What error channel_not_found means
Slack could not resolve the channel value you sent to any conversation this token can see. The documented description is deliberately narrow: "Value passed for channel was invalid." It is the single most-searched Slack API error, and in the overwhelming majority of cases the value is a channel name where a channel ID belongs. Slack conversation IDs look like C0123ABCDEF (public/private channels), D... (DMs), or G... (legacy groups/MPIMs); #general or general is a display label, accepted by some endpoints for convenience but not a stable identifier — renaming the channel breaks every integration that used the name.
The second major branch is visibility rather than format. A syntactically perfect ID still returns channel_not_found when the token cannot see the conversation: a private channel the bot has never been invited to, a DM that belongs to a different app's token, a conversation in another workspace of an Enterprise Grid org, or an ID copied from a different (staging) workspace. Slack does not distinguish "does not exist" from "exists but is invisible to you" — an information-leak-avoidance choice that means this error covers both.
The third branch is plumbing: the value never made it into the request. An undefined interpolated into JSON, an empty string from an unset environment variable, or a trailing newline from a config file all fail resolution. Since the HTTP status is 200, only body inspection reveals any of this.
Note the sibling for DMs: to message a user, you should not post to a bare user ID's DM without first calling conversations.open with that user ID and posting to the channel.id it returns; skipping that step on some paths surfaces as channel_not_found. In the SDKs it arrives as a plain platform error — ErrorCode.PlatformError with error.data.error === "channel_not_found" in @slack/web-api, SlackApiError with e.response["error"] in slack_sdk — and is never retried automatically, because it is deterministic.
What it looks like
POST /api/chat.postMessage
{"channel": "#general", "text": "hello"}
HTTP 200
{"ok": false, "error": "channel_not_found"}Why it happens
- A channel name (#general) was passed where a C-prefixed conversation ID is required.
- The bot cannot see the conversation: a private channel it was never invited to, or another app's DM.
- The ID comes from a different workspace (staging IDs in production, or the wrong workspace of a Grid org).
- The channel variable is empty or undefined at request time — the value was never populated.
- The channel was deleted, or for DMs, conversations.open was never called to establish the DM conversation ID.
- The ID was mangled in transit: truncated, lowercased, or wrapped in extra characters by templating.
How to fix Slack error channel_not_found
- 1Log the exact channel value sent (with quotes around it, so whitespace shows) and check the prefix: real IDs start with C, D, or G.
- 2Resolve names to IDs once via conversations.list (scope channels:read) and store the ID; in the Slack client, a channel's ID is at the bottom of its details pane.
- 3Verify visibility with conversations.info using the same token; if that also fails, the token cannot see the conversation.
- 4For private channels, have a member /invite the bot, then retry.
- 5For DMs, call conversations.open with the user ID and post to the returned channel.id.
- 6Confirm workspace identity with auth.test — the team field must match the workspace the ID came from.
How to stop it recurring
Store conversation IDs, never names, the moment you learn them (from events, conversations.list, or interactive payloads), and validate configured destinations with conversations.info at setup time so a bad ID fails during onboarding rather than at 3 a.m. Keep staging and production configuration strictly separated — cross-workspace IDs are this error's favorite disguise. The name-vs-ID trap is cause number one in Slack bot not responding.
Official reference: Slack API reference - chat.postMessage errors. See all Slack error codes or the Slack limits and quotas.
Related codes
- not_in_channel: Bot is not a member of the channelCannot post user messages to a channel they are not in.
- is_archived: Channel has been archivedChannel has been archived.
- user_not_found: Value(s) passed for users was invalidValue(s) passed for users was invalid.
- no_permission: Token lacks permission in this contextThe workspace token used in this request does not have the permissions…
- method_not_supported_for_channel_type: This conversation type can't be used hereThis type of conversation cannot be used with this method.
Error channel_not_found - quick answers
What does Slack error channel_not_found mean?
Slack could not resolve the channel value you sent to any conversation this token can see. The documented description is deliberately narrow: "Value passed for channel was invalid." It is the single most-searched Slack API error, and in the overwhelming majority of cases the value is a channel name where a channel ID belongs. Slack conversation IDs look like C0123ABCDEF (public/private channels), D... (DMs), or G...
How do I fix Slack error channel_not_found?
1. Log the exact channel value sent (with quotes around it, so whitespace shows) and check the prefix: real IDs start with C, D, or G. 2. Resolve names to IDs once via conversations.list (scope channels:read) and store the ID; in the Slack client, a channel's ID is at the bottom of its details pane. 3. Verify visibility with conversations.info using the same token; if that also fails, the token cannot see the conversation. 4. For private channels, have a member /invite the…
Should I retry after error channel_not_found?
No. Retrying the same request produces the same error; the condition has to be fixed first. Treat it as a permanent failure for that message and surface it, rather than looping.
Stop debugging Slack by hand
Connect the channel through Conferbot: tokens, webhooks and retries are handled, failures show as readable status.