binary-husky/gpt_academic · error · RuntimeError
获取Slack消息失败。
Error message
获取Slack消息失败。
What it means
A Slack API failure while fetching the bot's replies: get_slack_messages() calls conversations_history and wraps SlackApiError / KeyError in RuntimeError('获取Slack消息失败。'). SlackApiError means the Slack HTTP API returned an error payload (bad token, missing scope, invalid channel); KeyError means the response JSON lacked the expected 'messages' field.
Source
Thrown at request_llms/bridge_stackclaude.py:67
raise Exception("Channel not found.")
resp = await self.chat_postMessage(channel=self.CHANNEL_ID, text=text)
self.LAST_TS = resp["ts"]
async def get_slack_messages(self):
try:
# TODO:暂时不支持历史消息,因为在同一个频道里存在多人使用时历史消息渗透问题
resp = await self.conversations_history(
channel=self.CHANNEL_ID, oldest=self.LAST_TS, limit=1
)
msg = [
msg
for msg in resp["messages"]
if msg.get("user") == get_conf("SLACK_CLAUDE_BOT_ID")
]
return msg
except (SlackApiError, KeyError) as e:
raise RuntimeError(f"获取Slack消息失败。")
async def get_reply(self):
while True:
slack_msgs = await self.get_slack_messages()
if len(slack_msgs) == 0:
await asyncio.sleep(0.5)
continue
msg = slack_msgs[-1]
if msg["text"].endswith("Typing…_"):
yield False, msg["text"]
else:
yield True, msg["text"]
break
except:
pass
View on GitHub (pinned to d6bde0fa54)
Solutions
- Verify SLACK_CLAUDE_USER_TOKEN is valid: curl -H 'Authorization: Bearer <token>' https://slack.com/api/auth.test
- Add the required read scope (im:history / channels:history) to the token and reinstall the app
- Check you are not rate-limited: the get_reply loop polls every 0.5s, back off if Slack returns 429
- Catch SlackApiError and log e.response['error'] to see the exact Slack code (invalid_auth, channel_not_found, missing_scope, ratelimited)
Example fix
# before
except (SlackApiError, KeyError) as e:
raise RuntimeError(f"获取Slack消息失败。")
# after
except SlackApiError as e:
raise RuntimeError(f"获取Slack消息失败: {e.response['error']}") from e
except KeyError as e:
raise RuntimeError(f"获取Slack消息失败: unexpected payload, missing {e}") from e Defensive patterns
Strategy: try-catch
Validate before calling
from slack.errors import SlackApiError test = await client.conversations_history(channel=client.CHANNEL_ID, limit=1) assert 'messages' in test, 'unexpected Slack payload shape'
Try / catch
try:
msgs = await client.get_slack_messages()
except RuntimeError:
logger.exception('conversations_history failed; token/scopes/rate-limit?')
await asyncio.sleep(2) # back off, loop continues
except Exception:
raise Prevention
- Log e.response['error'] from SlackApiError instead of swallowing it
- Back off (exponential) when Slack returns 429 in the polling loop
- Run auth.test on the token at startup to catch revocation early
When it happens
Trigger: conversations_history(channel=CHANNEL_ID, oldest=LAST_TS, limit=1) failing inside the get_reply() polling loop of request_llms/bridge_stackclaude.py:67 — e.g. expired/revoked SLACK_CLAUDE_USER_TOKEN, token without channels:history scope, CHANNEL_ID pointing to an inaccessible channel, or Slack returning an error shape without resp['messages'].
Common situations: User token rotated or revoked after setup; bot removed from workspace; missing history scope on the legacy token; Slack rate limit (429) during the 0.5s polling loop; CHANNEL_ID stale after workspace migration.
Related errors
AI-assisted analysis of binary-husky/gpt_academic@d6bde0fa54 (2026-08-14).
Data as JSON: /api/errors/ec614ded5c50482e.
Report an issue: GitHub.