Skip to content

slack_file image blocks appended with chat.appendStream render as missing images inline #1961

Description

@sealogfish

Description

When an image block referencing a Slack-hosted file is appended to a streaming message using chat.appendStream, Slack initially renders a missing-image placeholder.

Clicking the missing image opens and displays the correct image, which indicates that:

  • The file ID is valid.
  • The upload completed successfully.
  • Slack generated the image thumbnail.
  • The original image remains accessible.

The same streamed message's DOM contains a valid Slack thumbnail URL, but Slack replaces the inline background image with an unable-to-load-error asset.

This may be a server-side file-sharing/association issue specific to blocks appended through the streaming APIs.

Reproducible in:

The Slack SDK version

3.43.0

Bot scopes:

  • chat:write
  • files:read
  • files:write

Python runtime version

3.13.7

OS info

ProductName: macOS
ProductVersion: 26.6.2
BuildVersion: 25G83

Steps to reproduce:

(Share the commands to run, source code, and project settings (e.g., pyproject.toml))

  1. Upload a PNG to Slack without posting a separate file message:
upload_response = await client.files_upload_v2(
    content=png_bytes,
    filename="sample.png",
)

file_id = upload_response["file"]["id"]
  1. Wait until files.info reports that the image and its thumbnail are ready:
file_info = await client.files_info(file=file_id)
file = file_info["file"]

assert file["mimetype"] == "image/png"
assert file["filetype"] == "png"
assert file["thumb_360"]
assert file["thumb_360_w"]
assert file["thumb_360_h"]
  1. Start a streaming message:
response = await client.chat_startStream(
    channel=channel_id,
    thread_ts=thread_ts,
)

stream_ts = response["ts"]
  1. Append an image block using the Slack file ID:
await client.chat_appendStream(
    channel=channel_id,
    ts=stream_ts,
    chunks=[
        {
            "type": "blocks",
            "blocks": [
                {
                    "type": "image",
                    "slack_file": {
                        "id": file_id,
                    },
                    "alt_text": "Sample Image",
                }
            ],
        }
    ],
)
  1. Stop the stream:
await client.chat_stopStream(
    channel=channel_id,
    ts=stream_ts,
)

Expected result:

The Slack-hosted image should render inline in the completed streaming message.

Actual result:

Slack renders a missing-image placeholder.
Clicking the placeholder opens and displays the correct image.
Inspecting the rendered HTML shows that Slack resolved the file to a generated thumbnail URL:

<a
  class="c-link c-message_attachment__image"
  href="https://files.slack.com/files-tmb/.../chart_480.png"
  style="
    background-image:
      url('https://a.slack-edge.com/.../unable-to-load-error-....png');
  "
>
  <span role="img" aria-label="missing image"></span>
</a>
Image

The href points to the generated Slack thumbnail, while the inline background is replaced with Slack's unable-to-load-error image.

Requirements

For general questions/issues about Slack API platform or its server-side, could you submit questions at https://my.slack.com/help/requests/new instead. 🙇

Please read the Contributing guidelines and Code of Conduct before creating this issue or pull request. By submitting, you are agreeing to those rules.

Activity

  1. WilliamBergamin commented on Sep 9, 2026

    @WilliamBergamin
    Contributor

    Thanks for the detailed repro, @sealogfish 🥇

    I followed your steps but couldn't reproduce the broken image, so I'm hoping you can help close the gap.

    I uploaded, polled files.info until the thumbnails were ready, then sent the image block via chat.appendStream (blocks chunk) in both a DM and a channel with thread_ts. It rendered fine in every case, live and finalized. On the API side, files.info(...).shares showed the file shared into the conversation and conversations.replies returned an intact image block with a populated image_url, so the association looks correct in my testing.

    To pin down what's different about your setup:

    • Which client shows the broken thumbnail (desktop / web / mobile) and its version?
    • Does it persist after a full page reload, or only appear during the live stream?
    • Single workspace or Enterprise Grid, and is the file shared across workspaces?

    Happy to dig in once I can see the failing request

  2. added
    needs infoAn issue that is claimed to be a bug and hasn't been reproduced, or otherwise needs more info
    and removed on Sep 9, 2026
  3. sealogfish commented on Sep 10, 2026

    @sealogfish
    Author

    Hi @WilliamBergamin,

    1. I tried this on both web (Chrome) and Desktop (Mac Version 4.51.191
      c745cdd438f19de75478cb2dee3d5e2532c0c3b8@1788997653) but it was happening for both
    2. After reloading, the issue doesn't persist and the image renders. It seems to always occur during the initial stream.
    3. Single workspace. To my understanding, the file should be a private file only available in the DM since I didn't specify any channels/thread parameters. How do I best verify if the file is shared across workspaces?

    I did try specifying the channel argument in files_upload_v2(). This results in a upload in the channel (DM) directly, before the file is appended to the stream. However, both images still render properly. The reason for not specifying channel/thread in the function call is because I would like to do formatting of the blocks first before streaming it to the user.

    I was also observing the network logs and it seems like the first files.info returns file_not_found. I don't think this is my code calling the API as there is a subsequent call after that succeeds, and I don't see any logs on my end that suggest that I tried.
    Image

  4. WilliamBergamin commented on Sep 10, 2026

    @WilliamBergamin
    Contributor

    Thanks for sharing more information 🙏 I tried reproducing this again but got the same behavior as before, this could be an edge case related to how the app is installed on an organization

    I reported this issue internally, hopefully we can get to the bottom of this!

    There isn't much we can do inside python-slack-sdk to patch this since it seems like a server side/frontend, but you can also report this through support@slack.com

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs infoAn issue that is claimed to be a bug and hasn't been reproduced, or otherwise needs more infoserver-side-issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions