ZhuLinsen/daily_stock_analysis · error · RuntimeError
result1.get('error', 'unknown')
Error message
result1.get('error', 'unknown') What it means
RuntimeError raised in the Slack sender's image upload flow when the files.getUploadURLExternal API call returns ok=false. The raised message is the Slack error code from the response (retrieved via result1.get('error','unknown')), such as invalid_auth, channel_not_found, or file_not_found. It aborts the report-image notification for that send.
Source
Thrown at src/notification_sender/slack_sender.py:204
"""
# Bot 模式:使用新版文件上传 API
if self._use_bot:
headers = {'Authorization': f'Bearer {self._slack_bot_token}'}
try:
# Step 1: 获取上传 URL
resp1 = requests.post(
'https://slack.com/api/files.getUploadURLExternal',
headers=headers,
data={
'filename': 'report.png',
'length': len(image_bytes),
},
timeout=30,
)
result1 = resp1.json()
if not result1.get("ok"):
logger.error("Slack 获取上传 URL 失败: %s", result1.get('error', 'unknown'))
raise RuntimeError(result1.get('error', 'unknown'))
upload_url = result1['upload_url']
file_id = result1['file_id']
# Step 2: 上传文件内容(raw body,不能用 multipart)
resp2 = requests.post(
upload_url,
data=image_bytes,
headers={'Content-Type': 'application/octet-stream'},
timeout=30,
)
if resp2.status_code != 200:
logger.error("Slack 文件上传失败: HTTP %s", resp2.status_code)
raise RuntimeError(f"HTTP {resp2.status_code}")
# Step 3: 完成上传并分享到频道
resp3 = requests.post(
'https://slack.com/api/files.completeUploadExternal',View on GitHub (pinned to 5159bd72e8)
Solutions
- Check the logged Slack error code right before the raise — it names the exact cause
- For auth errors, refresh SLACK_BOT_TOKEN and ensure the app has chat:write and files:write scopes, then reinstall the app in the workspace
- For channel errors, verify SLACK_CHANNEL_ID and invite the bot to that channel (/invite @bot)
- For missing_scope, add the required scopes in the Slack app config and re-authorize
Defensive patterns
Strategy: try-catch
Validate before calling
def slack_token_looks_valid(token: str) -> bool:
return bool(token) and token.startswith("xoxb-") and len(token) > 20 Try / catch
try:
sender.send_image(channel_id, image_bytes)
except RuntimeError as exc:
if str(exc) in {"invalid_auth", "token_expired", "account_inactive"}:
alert_ops("Slack token invalid/expired — rotate SLACK_BOT_TOKEN")
elif str(exc) in {"channel_not_found", "not_in_channel"}:
alert_ops(f"Slack bot lacks access to channel {channel_id}")
raise Prevention
- Verify the bot token and files:write/chat:write scopes at app startup with an auth.test call
- Invite the bot to the target channel as part of setup runbooks
- Monitor Slack token rotation events and rotate config proactively
When it happens
Trigger: POSTing to https://slack.com/api/files.getUploadURLExternal with a bad/expired bot token (invalid_auth, token_expired), a bot not invited to the target channel (channel_not_found / not_in_channel), missing files:write scope (missing_scope), or an invalid length parameter. Any ok=false response triggers it.
Common situations: Rotated or revoked Slack bot tokens; forgetting to reinstall the Slack app after adding the files:write OAuth scope; the bot was never invited to the configured channel; workspace admins revoked the app; token for a different workspace than the channel.
Related errors
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/7a40ddf270aa0d27.
Report an issue: GitHub.