openclaw - 💡(How to fix) Fix Slack DM read path ignores userToken and uses bot token only [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#59246Fetched 2026-04-08 02:26:57
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Author
Participants

Slack DM history reads appear to ignore the configured userToken and always use the bot token. This breaks DM readback even when sending works and a read-capable userToken is configured on the Slack account.

Error Message

An API error occurred: channel_not_found An API error occurred: missing_scope

Root Cause

Likely root cause

The Slack read path appears to always resolve the bot token.

Code Example

{
  "action": "read",
  "channel": "slack",
  "channelId": "D0AQ59TGMU3",
  "accountId": "reese",
  "limit": 10
}

---

An API error occurred: channel_not_found

---

An API error occurred: missing_scope

---

async function readSlackMessages(channelId, opts = {}) {
  const client = await getClient(opts);
  ...
  const result = await client.conversations.history({
    channel: channelId,
    ...
  });
}

---

async function getClient(opts = {}, mode = "read") {
  const token = resolveToken(opts.token, opts.accountId);
  return opts.client ?? (mode === "write" ? createSlackWriteClient(token) : createSlackWebClient(token));
}

---

function resolveToken(explicit, accountId) {
  const account = resolveSlackAccount({
    cfg: loadConfig(),
    accountId
  });
  const token = resolveSlackBotToken(explicit ?? account.botToken ?? void 0);
  ...
}
RAW_BUFFERClick to expand / collapse

Summary

Slack DM history reads appear to ignore the configured userToken and always use the bot token. This breaks DM readback even when sending works and a read-capable userToken is configured on the Slack account.

Environment

  • OpenClaw 2026.3.31 (213a704)
  • Slack channel integration in Socket Mode
  • Multi-account Slack config
  • channels.slack.defaultAccount = "reese"
  • channels.slack.accounts.reese.userToken configured
  • channels.slack.accounts.reese.botToken configured

Observed behavior

What works

  • Sending a DM to a Slack user works
  • Manual reactions work
  • Ack reactions work in Slack DM

What fails

Reading the DM thread back via the message/read tool fails.

Repro from an active install:

  1. Send a DM explicitly from Slack account reese to user U03B98862MV
  2. OpenClaw returns:
    • messageId: 1775076461.846699
    • channelId: D0AQ59TGMU3
  3. Immediately call Slack read on that exact channel and account:
{
  "action": "read",
  "channel": "slack",
  "channelId": "D0AQ59TGMU3",
  "accountId": "reese",
  "limit": 10
}
  1. Result:
An API error occurred: channel_not_found

Earlier attempts against the same DM also produced:

An API error occurred: missing_scope

Expected behavior

When a Slack account has a configured userToken, Slack read operations (especially DM history reads) should prefer the user token or otherwise honor the documented read-token behavior, rather than forcing bot-token-only reads.

Likely root cause

The Slack read path appears to always resolve the bot token.

Relevant code in the built distribution:

probe--IEvIVqV.js

async function readSlackMessages(channelId, opts = {}) {
  const client = await getClient(opts);
  ...
  const result = await client.conversations.history({
    channel: channelId,
    ...
  });
}
async function getClient(opts = {}, mode = "read") {
  const token = resolveToken(opts.token, opts.accountId);
  return opts.client ?? (mode === "write" ? createSlackWriteClient(token) : createSlackWebClient(token));
}
function resolveToken(explicit, accountId) {
  const account = resolveSlackAccount({
    cfg: loadConfig(),
    accountId
  });
  const token = resolveSlackBotToken(explicit ?? account.botToken ?? void 0);
  ...
}

The key issue is that resolveToken() resolves the bot token only, even for read operations.

Why this seems wrong

The docs suggest user tokens can be preferred for actions/directory reads when configured, but this read path never appears to consult userToken.

Impact

  • DM send/read symmetry breaks
  • outbound DM workflows cannot reliably verify responses/history
  • multi-account Slack setups are especially confusing because send works but immediate readback fails

Suggested fix

Split Slack client token resolution by mode:

  • for read operations, prefer configured userToken when available and allowed
  • for write operations, continue preferring bot token

If intentional, docs should clearly state that message read on Slack DMs is bot-token-only and may fail even when a userToken exists.

extent analysis

TL;DR

Modify the resolveToken function to prefer the userToken for read operations when available.

Guidance

  • Update the resolveToken function to check for the userToken when the mode is "read" and the userToken is configured for the account.
  • Ensure the resolveToken function returns the userToken for read operations if it exists, instead of always returning the bot token.
  • Verify the fix by testing the read operation with a configured userToken and checking if the channel_not_found and missing_scope errors are resolved.
  • Review the documentation to ensure it accurately reflects the token preference behavior for read and write operations.

Example

function resolveToken(explicit, accountId, mode) {
  const account = resolveSlackAccount({
    cfg: loadConfig(),
    accountId
  });
  if (mode === "read" && account.userToken) {
    return account.userToken;
  }
  const token = resolveSlackBotToken(explicit ?? account.botToken ?? void 0);
  ...
}

Notes

The suggested fix assumes that the userToken has the necessary scopes for read operations. If the userToken is missing required scopes, additional configuration or token setup may be necessary.

Recommendation

Apply the workaround by modifying the resolveToken function to prefer the userToken for read operations. This change should resolve the channel_not_found and missing_scope errors and ensure that DM readback works as expected when a userToken is configured.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

When a Slack account has a configured userToken, Slack read operations (especially DM history reads) should prefer the user token or otherwise honor the documented read-token behavior, rather than forcing bot-token-only reads.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix Slack DM read path ignores userToken and uses bot token only [1 participants]