Skip to content

[Bug]: Repro: Slack file downloads still land as HTML sign-in pages in image_cache and break vision #7015

@xinbenlv

Description

@xinbenlv

Original Request

把我们的情况写成一个单独的bug report提上去,用 /fr 记得reference已知的。
English Translation: File our situation as a separate bug report, using the /fr style, and remember to reference known issues.

Agent's Two Cents (could be wrong)

Everything below is the AI agent's best guess based on the current codebase.
Take with a grain of salt — the original request above is the only thing that came from a human.

Problem / Motivation

Slack image attachments can still arrive at Hermes as local *.png files that are actually Slack HTML sign-in / redirect pages. That makes the agent think it has a real image path, then fail later inside vision_analyze, which is the wrong boundary and the wrong error.

This report is separate from the already-filed issue because we reproduced it again in a real Slack thread with fresh cached files and confirmed the bad payload contents locally.

What We Checked

  • Reproduced twice in a live Slack-backed Hermes session using cached paths under ~/.hermes/image_cache/.
  • Verified both cached *.png files were actually HTML via file, hex dump, and failed PIL open.
  • Confirmed the HTML contains Slack sign-in / workspace redirect content, including <title>Slack</title> and workspace-signin.
  • Checked the current Slack adapter path: gateway/platforms/slack.py downloads bytes from url_private_download and caches them without validating that the payload is genuinely image/file content.
  • Confirmed related existing issue: [Bug]: Slack image attachments can be cached as HTML sign-in pages, causing downstream vision failures #6829.

Proposed Solution

Validate Slack download payloads at the Slack gateway boundary before caching:

  • reject text/html responses,
  • reject obvious HTML bodies even if headers are wrong,
  • avoid caching bogus bytes as image/file attachments,
  • surface a Slack media download/auth/access error immediately instead of handing a fake image path to vision.

Dependencies & Potential Blockers

No major blockers identified.

How to Validate

  • Send an image attachment to Hermes in Slack.
  • If Slack returns a real image, Hermes should cache and analyze it normally.
  • If Slack returns an HTML sign-in/redirect page, Hermes should reject it before caching it as an image.
  • vision_analyze should never receive a bogus local image path created from HTML bytes.
  • Add a regression test for HTTP 200 + HTML body from Slack file URLs.

Best Validation Path

Run the Slack media retry/regression tests after adding the payload validator:

source venv/bin/activate
python -m pytest tests/gateway/test_media_download_retry.py -q

Then manually reproduce with a Slack image attachment and confirm Hermes either analyzes a real image or reports a Slack download error without writing HTML-as-image into ~/.hermes/cache/images/ or legacy ~/.hermes/image_cache/.

Best Human Demo

A short before-vs-after terminal demo:

  1. show file ~/.hermes/image_cache/img_*.png returning HTML document text before the fix,
  2. reproduce the same Slack attachment flow after the fix,
  3. show that no bogus cached image is produced and the error is reported at download time.

Scope Estimate

small

Key Files/Modules Likely Involved

  • gateway/platforms/slack.py
  • gateway/platforms/base.py
  • tests/gateway/test_media_download_retry.py
  • tools/vision_tools.py

Architecture Diagram

Slack file URL
    |
    v
SlackAdapter._download_slack_file/_bytes
    |
    |  (today: trusts HTTP 200 too much)
    v
cache_image_from_bytes / cache_document_from_bytes
    |
    v
local ~/.hermes/cache/images or ~/.hermes/image_cache
    |
    v
agent receives local path
    |
    v
vision_analyze
    |
    v
late failure: "Only real image files are supported"

Desired fix:
Slack file URL
    |
    v
SlackAdapter download
    |
    +--> payload validation (content-type + HTML sniff)
            |
            +--> reject early with Slack download/auth/access error
            |
            \--> only real media bytes reach cache

Rough Implementation Sketch

  • Add a small payload validator in gateway/platforms/slack.py.
  • Check response headers plus a lightweight HTML sniff on the first bytes.
  • Call that validator from both _download_slack_file(...) and _download_slack_file_bytes(...).
  • Add regression tests covering 200 OK + HTML response for image and raw-file download paths.

Open Questions

  • Whether Slack is returning HTML because of token scope, workspace session state, or a URL/access mode edge case.
  • Whether other platform adapters should get the same defense-in-depth guard.

Potential Risks or Gotchas

  • Header-only validation is not enough; some bad responses may still claim a generic content type.
  • Overly strict validation could reject unusual but valid payloads, so the guard should focus on obviously HTML responses.

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/gatewayGateway runner, session dispatch, deliveryplatform/slackSlack app adaptertool/visionVision analysis and image generationtype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions