Repository navigation
Uploaded files are not appearing in channel and do not contain mimetype #1575
Description
Activity
Hi @nobikin95 - I noticed that the successful output has
is_public: false, and the channels array is empty. What was your output for the files.completeUploadExternal request? I just want to check here that you supplied the channel_id, otherwise the file will be private.- addedquestionM-T: User needs support to use the projectM-T: User needs support to use the projectand removed
on Oct 25, 2024 Hi @srajiang, output for the files.completeUploadExternal :
"ok": true, "files": [ { "id": "xxxxxxx", "created": 1729847794, "timestamp": 1729847794, "name": "xxxxxxxxxxxxx.xxx", "title": "xxxxxxxxxxx.xxx", "mimetype": "", "filetype": "", "pretty_type": "", "user": "xxxxxxxxx", "user_team": "xxxxxxxxx", "editable": false, "size": 61652512, "mode": "hosted", "is_external": false, "external_type": "", "is_public": false, "public_url_shared": false, "display_as_bot": false, "username": "", "url_private": "https://files.slack.com/files-pri/XXXXXXXXXXXXX-XXXXXXXXXXX/xxxxxxxxxxxxxxxxx.xxx", "url_private_download": "https://files.slack.com/files-pri/XXXXXXXXXXXXX-XXXXXXXXXXX/download/xxxxxxxxxxxxxxxxx.xxx", "media_display_type": "unknown", "permalink": "https://ikameglobal.slack.com/files/XXXXXXXXXXXXX/XXXXXXXXXXXXX/xxxxxxxxxxxxxxxxx.xxx", "permalink_public": "https://slack-files.com/XXXXXXXXXXXXX-XXXXXXXXXXXXX-xxxxxxxxxx", "comments_count": 0, "is_starred": false, "shares": {}, "channels": [], "groups": [], "ims": [], "has_more_shares": false, "has_rich_preview": false, "file_access": "visible" } ] }It seems like I'm having an issue with channel_id, here is the code I'm using:
#!/bin/bash FILE_PATH=$1 CHANNEL_ID="XXXXXXXXXXX" USER_TOKEN="xoxp-" BOT_TOKEN="xoxb-" # Check if the file exists echo "Checking if file exists at: $FILE_PATH" if [ ! -f "$FILE_PATH" ]; then echo "Error: File $FILE_PATH does not exist!" exit 1 fi echo "File found at: $FILE_PATH" # Get file size (use command compatible with macOS and Linux) if [[ "$OSTYPE" == "darwin"* ]]; then FILE_SIZE=$(stat -f%z "$FILE_PATH") else FILE_SIZE=$(stat -c%s "$FILE_PATH") fi # Step 1: Get upload URL using the files.getUploadURLExternal API echo "Fetching upload URL from Slack API..." UPLOAD_URL_RESPONSE=$(curl -s -X POST \ -H "Authorization: Bearer $USER_TOKEN" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data "filename=$(basename "$FILE_PATH")&length=$FILE_SIZE&channels=$CHANNEL_ID" \ https://slack.com/api/files.getUploadURLExternal) # Log the response from the API echo "Response from files.getUploadURLExternal: $UPLOAD_URL_RESPONSE" # Extract upload URL and file_id from JSON response UPLOAD_URL=$(echo "$UPLOAD_URL_RESPONSE" | grep -o '"upload_url":"[^"]*' | sed 's/"upload_url":"//g' | sed 's/\\//g') FILE_ID=$(echo "$UPLOAD_URL_RESPONSE" | grep -o '"file_id":"[^"]*' | sed 's/"file_id":"//g') # Check if the URL or file_id was not obtained if [ -z "$UPLOAD_URL" ] || [ -z "$FILE_ID" ]; then echo "Error: Failed to get upload URL or file_id" exit 1 fi echo "Upload URL: $UPLOAD_URL" echo "File ID: $FILE_ID" # Step 2: Upload the file to the obtained URL echo "Uploading file to: $UPLOAD_URL" UPLOAD_RESULT=$(curl -s -X PUT \ -H "Content-Type: application/octet-stream" \ --data-binary @"$FILE_PATH" \ "$UPLOAD_URL") # Log the upload result echo "Result of file upload: $UPLOAD_RESULT" # Step 3: Complete the upload using the files.completeUploadExternal API echo "Completing file upload with Slack API..." COMPLETE_RESPONSE=$(curl -s -X POST \ -H "Authorization: Bearer $USER_TOKEN" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "files=[{\"id\":\"$FILE_ID\"}]" \ --data-urlencode "channels=$CHANNEL_ID" \ https://slack.com/api/files.completeUploadExternal) # Log the response from the files.completeUploadExternal API echo "Response from files.completeUploadExternal: $COMPLETE_RESPONSE" # Step 3.1: Share the public URL using the files.sharedPublicURL API echo "Sharing file publicly using Slack API..." SHARED_PUBLIC_URL_RESPONSE=$(curl -s -X POST \ -H "Authorization: Bearer $USER_TOKEN" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data "file=$FILE_ID" \ https://slack.com/api/files.sharedPublicURL) # Log the response from the files.sharedPublicURL API echo "Response from files.sharedPublicURL: $SHARED_PUBLIC_URL_RESPONSE" # Extract URL from JSON response (use permalink instead of permalink_public) PUBLIC_URL=$(echo "$SHARED_PUBLIC_URL_RESPONSE" | grep -o '"permalink_public":"[^"]*' | sed 's/"permalink_public":"//g' | sed 's/\\//g') # Check if the URL was not obtained if [ -z "$PUBLIC_URL" ]; then echo "Error: Failed to get permalink URL" exit 1 fi echo "Public URL: $PUBLIC_URL" # Step 4: Post a message to the channel with the uploaded file using chat.postMessage API echo "Posting message to channel with uploaded file ..." POST_MESSAGE_RESPONSE=$(curl -s -X POST \ -H "Authorization: Bearer $USER_TOKEN" \ -H "Content-Type: application/json" \ --data "$(cat <<EOF { "channel": "$CHANNEL_ID", "text": "Build Success: <$PUBLIC_URL>", "attachments": [ { "title": "Click here to download", "title_link": "$PUBLIC_URL", "text": "The file is available for public download." } ] } EOF )" \ https://slack.com/api/chat.postMessage) # Log the response from the chat.postMessage API echo "Response from chat.postMessage: $POST_MESSAGE_RESPONSE"The cause of your confusion may not be related to this, but the
files.completeUploadExternalAPI processes its tasks asynchronously. This means that if a subsequent operation attempts to download the uploaded file immediately, it might fail until thefiles.completeUploadExternaloperation completes. It appears that your code is trying to download the files right away. In most cases, this can fail regardless of whether the files are public or private.One way to determine if the upload operation is finished is to check if the "shares" property is available in the file's metadata. You can verify this by polling the
files.infoAPI with the uploaded file's ID.Reacted by Nick Bellgithub-actions commented
on Dec 2, 2024 on Dec 2, 2024 – with GitHub Actions · Hidden as outdatedshow commentMore actionsI've been stumped by this api. My file gets uploaded and I've set the channel_id but it still is not seeing it in the channel. From the documentation it seems like the file should show up in the channel but perhaps that is not the case?
calling
files.completeUploadExternal(I'm using Elixir) with this body:%{ files: [%{id: "xxxxxxxxx", title: "Galaxy Book Pro.pdf"}], thread_ts: "xxxxxxxx.xxxxxx", initial_comment: "Attachments", channel_id: "xxxxxxxxxx" }I get this response:
%{ "files" => [ %{ "filetype" => "", "mode" => "hosted", "comments_count" => 0, "public_url_shared" => false, "file_access" => "visible", "is_starred" => false, "channels" => [], "url_private" => "https://files.slack.com/files-pri/xxxxxxxx-xxxxxxxx/galaxy_book_pro.pdf", "url_private_download" => "https://files.slack.com/files-pri/xxxxxxxx-xxxxxxxx/download/galaxy_book_pro.pdf", "created" => 1733998180, "media_display_type" => "unknown", "external_type" => "", "mimetype" => "", "has_rich_preview" => false, "pretty_type" => "", "ims" => [], "groups" => [], "shares" => %{}, "name" => "Galaxy Book Pro.pdf", "id" => "xxxxxxxxxxx", "display_as_bot" => false, "user" => "xxxxxxxxxx", "size" => 45061, "has_more_shares" => false, "permalink_public" => "https://slack-files.com/xxxxxxxx-xxxxxxx-xxxxxxx", "timestamp" => 1733998180, "user_team" => "xxxxxxxxx", "permalink" => "https://upptec.slack.com/files/xxxxxxxx/xxxxxxxx/galaxy_book_pro.pdf", "title" => "Galaxy Book Pro.pdf", "is_external" => false, "username" => "", "editable" => false, "is_public" => false } ], "ok" => true }Using
files.infoI can find the file:{ "ok": true, "file": { "id": "xxxxxxxxxx", "created": 1733998180, "timestamp": 1733998180, "name": "Galaxy Book Pro.pdf", "title": "Galaxy Book Pro.pdf", "mimetype": "", "filetype": "", "pretty_type": "", "user": "xxxxxxxxxx", "user_team": "xxxxxxxx", "editable": false, "size": 45061, "mode": "hosted", "is_external": false, "external_type": "", "is_public": false, "public_url_shared": false, "display_as_bot": false, "username": "", "url_private": "https://files.slack.com/files-pri/xxxxxxx-xxxxxxx/galaxy_book_pro.pdf", "url_private_download": "https://files.slack.com/files-pri/xxxxxxxx-xxxxxxxx/download/galaxy_book_pro.pdf", "media_display_type": "unknown", "permalink": "https://X.slack.com/files/xxxxxxxxxx/xxxxxxxx/galaxy_book_pro.pdf", "permalink_public": "https://slack-files.com/xxxxxxxxx-xxxxxxxx-xxxxxx", "favorites": [], "is_starred": false, "shares": {}, "channels": [], "groups": [], "ims": [], "has_more_shares": false, "has_rich_preview": false, "file_access": "visible", "comments_count": 0 }, "comments": [], "response_metadata": { "next_cursor": "" } }Note: I've redacted ids
github-actions commented
on Jan 20, 2025 on Jan 20, 2025 – with GitHub Actions · Hidden as outdatedshow commentMore actions23 remaining items
@zimeg Sorry for the delay, we can see that mimetype is empty and the list of channels is also empty after calling
files.infobut the difference is that we never see that the file appears in the channel (not even after multiple days). The file has a permalink but when I try to access it I just get a blank screen.@sidkurella Likewise, I apologize for slow follow up here 🙏 ✨
I'm curious if slack-go/slack#1481 might hint at the cause of missing
mimetypebeing an unexpected length argument for the file size?A snippet of "broken" code might also be useful in troubleshooting! 🔍
@zimeg Sure, here's a snippet of the code:
func (n *Messenger) SendFileMessage(ctx context.Context, channel string, inputFile *os.File, initialComment string) { fileName := filepath.Base(inputFile.Name()) fileInfo, err := inputFile.Stat() if err != nil { n.log.Errorf("Could not send slack message to channel %s, skipping, err=%v", fileName, err) return } fileSize := int(fileInfo.Size()) request := slack.UploadFileV2Parameters{ Channel: channel, InitialComment: initialComment, Reader: inputFile, Filename: fileName, FileSize: fileSize, AltTxt: initialComment, Title: initialComment, SnippetType: "csv", } fileSummary, err := n.slackClient.UploadFileV2Context(ctx, request) if err != nil { n.log.Errorf("Could not send slack message to channel %s, skipping, err=%+v, msg=%s, request: %+v", channel, err, initialComment, request) } n.log.Infof("Successfully uploaded file to slack channel %s, file summary: %+v", channel, fileSummary) // clipped ...
We're not seeing any returned errors. Below this we call GetFileInfo:
file, comments, paging, err := n.slackClient.GetFileInfo(fileSummary.ID, 1, 1) if err != nil { n.log.Fatalf("file info failed: %v", err) } n.log.Debugf("File info: %+v, comments: %+v, paging: %+v", file, comments, paging)
and here we observe the following file info:
File info: &{ID:redacted Created:"Wed Nov 19" Timestamp:"Wed Nov 19" Name:redacted.csv Title:redacted Mimetype: ImageExifRotation:0 Filetype: PrettyType: User:redacted Mode:hosted Editable:false IsExternal:false ExternalType: Size:1718 URL: URLDownload: URLPrivate:https://files.slack.com/redacted URLPrivateDownload:https://files.slack.com/redacted OriginalH:0 OriginalW:0 Thumb64: Thumb80: Thumb160: Thumb360: Thumb360Gif: Thumb360W:0 Thumb360H:0 Thumb480: Thumb480W:0 Thumb480H:0 Thumb720: Thumb720W:0 Thumb720H:0 Thumb960: Thumb960W:0 Thumb960H:0 Thumb1024: Thumb1024W:0 Thumb1024H:0 Permalink:redacted PermalinkPublic:redacted EditLink: Preview: PreviewHighlight: Lines:0 LinesMore:0 IsPublic:false PublicURLShared:false Channels:[] Groups:[] IMs:[] InitialComment:{ID: Created:"Thu Jan 1" Timestamp:"Thu Jan 1" User: Comment:} CommentsCount:0 NumStars:0 IsStarred:false Shares:{Public:map[] Private:map[]} Subject: To:[] From:[] Cc:[] Headers:{Date: InReplyTo: ReplyTo: MessageID:}}The application can download the file from URLPrivateDownload but we see diffs when we download that, we're investigating further today. If I try to access the file via Permalink I get a blank screen that does show the correct title of the file though.
When we download that url we get some kind of sign-in page instead of the actual file (we're downloading in the same application that did the upload and it has files:read scope so I doubt it's a permissions error)
@sidkurella This is so appreciated! I'll plan to soon investigate this
goimplementation 👾When we download that url we get some kind of sign-in page instead of the actual file
The same token used when uploading a file must be included as an authorization header when downloading from the private download URL - #1434 - otherwise that authentication page is returned I do believe!
@zimeg Oops, yeah I was setting the Authorization header wrong. After setting it properly the downloaded file from URLPrivateDownload and the uploaded file are identical, but still not seeing it shared to any channels.
Reacted by Eden Zimbelman@sidkurella I'm finding luck with uploading the following code to a channel:
package main import ( "bytes" "fmt" "os" "github.com/slack-go/slack" ) func main() { token := os.Getenv("SLACK_BOT_TOKEN") api := slack.New(token) file, err := os.ReadFile("main.go") if err != nil { return } uploader := slack.UploadFileV2Parameters{ Channel: "C0123456789", FileSize: len(file), Filename: "main.go", Reader: bytes.NewReader(file), } response, err := api.UploadFileV2(uploader) if err != nil { return } fmt.Printf("File ID: %s\n", response.ID) }
Is it possible to confirm that the channel ID you're providing is included in the request if nothing else seems off? IIRC some limitations exist around file types allowed in Slack Connect channels, but this seems unrelated to me...
@zimeg Later in the code we log the channel ID and it matches so we're definitely including it. Note that we're getting a successful file ID but we can't see the file in the channel, you're not observing the same behavior?
Does it make a difference if the channel in question is a private channel? The bot is able to post messages to the channel though, not files.
@sidkurella Hmm... I'm finding the file appears in both public and private channels. FWIW this is with file size of
500bytes or so.I understand file uploads to require some processing on the backend and am curious if you're uploading large files? Uploads should still appear but I wonder if that might be causing issue 🤖
@zimeg They're not unreasonably large, our last try was around 1700 bytes or so, used to work fine with the old api
Reacted by Eden ZimbelmanReacted by Eden Zimbelman@sidkurella That's within reason for sure! Are these same issues happening with the above snippet I shared or with different files too?
@zimeg I can try your exact snippet some time Monday, this was occurring with the snippet I sent above but we've tried without snippet type or alt txt, as well as reading the whole file contents into a buffer and using that instead of the file directly with no luck. Since the file contents are being uploaded successfully (as evidenced by downloading from URLPrivateDownload) I'm skeptical that's the issue though.
@zimeg We managed to get it working by omitting AltTxt (which I guess we shouldn't have included since the file's not an image). Still, I wouldn't expect this kind of behavior in that case where the file is still uploaded but not shared to any channels (probably would have expected either an error or for this parameter to be ignored)
Reacted by Ben Soer, atanas-balevsky and Eden ZimbelmanReacted by Eden ZimbelmanHello wanted to add to the conversation that I had the same issue working with the python SDK. The fix was what @sidkurella described of removing the
alt_textfrom thefile.getUploadURLExternalcall.I was getting the same errors though of the slack api always saying my upload was part of no
sharesand nochannels. My testing right now only has attachments of log files with 5-10 lines.With alt text removed. The
sharesandchannelsin the response is empty still for me. But it is posting now in my slack channelsA snippet of my code (now working) for reference:
if logs: message_ts = postMessage_response.get('ts') channel_id = postMessage_response.get('channel') # Allocate upload space on Slack getUploadURLExternal_response = self.client.files_getUploadURLExternal( filename=f"logs_{event_data.involved_object.kind}_{event_data.involved_object.namespace}_{event_data.involved_object.name}.txt", length=len(logs), snippet_type="text" ) # Check allocation was successful ok = getUploadURLExternal_response.get("ok", False) if not ok: error = getUploadURLExternal_response.get("error") if error: self._logger.error(f"Slack files.getUploadURLExternal Failed for event {event_data.involved_object.namespace}/{event_data.involved_object.name} to Slack: {error}") return upload_url = getUploadURLExternal_response.get("upload_url") file_id = getUploadURLExternal_response.get("file_id") # Upload the actual log/file contents try: headers = { # This header tells the server we are sending raw bytes 'Content-Type': 'application/octet-stream' } upload_response = requests.post( upload_url, headers=headers, data=logs.encode('utf-8'), ) upload_response.raise_for_status() except Exception as e: self._logger.error(f"Failed to upload logs for event {event_data.involved_object.namespace}/{event_data.involved_object.name} to Slack", exc_info=e) return self._logger.debug("Sending To Channel ID: " + str(channel_id)) # Complete the upload process, posting the logs as a thread to the original message completeUploadExternal_response = self.client.files_completeUploadExternal( upload_url=upload_url, channel_id=str(channel_id), channels=[str(channel_id)], thread_ts=message_ts, initial_comment="Attached logs for the Kubernetes event:", files=[ { "id": file_id, "title": f"logs_{event_data.involved_object.kind}_{event_data.involved_object.namespace}_{event_data.involved_object.name}.txt", } ] )
I am uploading files using files.completeUploadExternal.
The API returns ok: true, and files.info confirms the file exists.
However, the file is never shared to the channel — channels, groups, and ims remain empty even when channel_id is provided.I understand now that files.completeUploadExternal only completes the upload and does not actually share the file to a channel.
I also tried chat.postMessage, but it only posts file links. Videos do not play inline and appear empty.
curl --location 'https://slack.com/api/files.completeUploadExternal'
--header 'Authorization: Bearer xoxb-XXXXXXX'
--header 'Content-Type: application/json'
--header 'Cookie: b=XXXXXX; utm=%7B%7D'
--data '{"files":[{"id":"XXXXXX"}],"channel_id":"XXXXX","initial_comment":"Hi"}'response:-
{
"ok": true,
"files": [
{
"id": "XXXXXX",
"created": 1768889654,
"timestamp": 1768889654,
"name": "failure.png",
"title": "failure.png",
"mimetype": "",
"filetype": "",
"pretty_type": "",
"user": "XXXXXX",
"user_team": "XXXXX",
"editable": false,
"size": 61294,
"mode": "hosted",
"is_external": false,
"external_type": "",
"is_public": false,
"public_url_shared": false,
"display_as_bot": false,
"username": "",
"url_private": "https://files.slack.com/files-pri/XXXXXX/failure.png",
"url_private_download": "https://files.slack.com/files-pri/XXXXXX/download/failure.png",
"media_display_type": "unknown",
"permalink": "https://justlifeteam.slack.com/files/XXXXXXX/failure.png",
"permalink_public": "https://slack-files.com/XXXXXXX",
"comments_count": 0,
"is_starred": false,
"shares": {},
"channels": [],
"groups": [],
"ims": [],
"has_more_shares": false,
"has_rich_preview": false,
"file_access": "visible"
}
],
"warning": "missing_charset",
"response_metadata": {
"warnings": [
"missing_charset"
]
}
}
I am trying to upload a file to a private Slack channel using the Slack API via the following Python script.
However, once uploaded, the file cannot be downloaded by users in the channel. I am looking for help to understand why this is happening and how to resolve it.
Python runtime version
3.12.1
I used these step:
Actual result: