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

  1. Check the logged Slack error code right before the raise — it names the exact cause
  2. 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
  3. For channel errors, verify SLACK_CHANNEL_ID and invite the bot to that channel (/invite @bot)
  4. 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

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.