You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Uploaded files are not appearing in channel and do not contain mimetype #1575
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.
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.
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.completeUploadExternal API processes its tasks asynchronously. This means that if a subsequent operation attempts to download the uploaded file immediately, it might fail until the files.completeUploadExternal operation 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.info API with the uploaded file's ID.
I'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:
@zimeg Sorry for the delay, we can see that mimetype is empty and the list of channels is also empty after calling files.info but 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.
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 go implementation 👾
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.
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 500 bytes 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 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 Zimbelman
Hello 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_text from the file.getUploadURLExternal call.
I was getting the same errors though of the slack api always saying my upload was part of no shares and no channels. My testing right now only has attachments of log files with 5-10 lines.
With alt text removed. The shares and channels in the response is empty still for me. But it is posting now in my slack channels
A snippet of my code (now working) for reference:
iflogs:
message_ts=postMessage_response.get('ts')
channel_id=postMessage_response.get('channel')
# Allocate upload space on SlackgetUploadURLExternal_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 successfulok=getUploadURLExternal_response.get("ok", False)
ifnotok:
error=getUploadURLExternal_response.get("error")
iferror:
self._logger.error(f"Slack files.getUploadURLExternal Failed for event {event_data.involved_object.namespace}/{event_data.involved_object.name} to Slack: {error}")
returnupload_url=getUploadURLExternal_response.get("upload_url")
file_id=getUploadURLExternal_response.get("file_id")
# Upload the actual log/file contentstry:
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()
exceptExceptionase:
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)
returnself._logger.debug("Sending To Channel ID: "+str(channel_id))
# Complete the upload process, posting the logs as a thread to the original messagecompleteUploadExternal_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.
Activity
srajiang commentedon Oct 25, 2024
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.nobikin95 commentedon Oct 28, 2024
Hi @srajiang, output for the files.completeUploadExternal :
nobikin95 commentedon Oct 28, 2024
It seems like I'm having an issue with channel_id, here is the code I'm using:
seratch commentedon Oct 28, 2024
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.github-actions commentedon Dec 2, 2024
honungsburk commentedon Dec 12, 2024
I'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:I get this response:
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 commentedon Jan 20, 2025
23 remaining items
sidkurella commentedon Nov 19, 2025
@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.zimeg commentedon Nov 20, 2025
@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! 🔍
sidkurella commentedon Nov 20, 2025
@zimeg Sure, here's a snippet of the code:
We're not seeing any returned errors. Below this we call GetFileInfo:
and here we observe the following file info:
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.
sidkurella commentedon Nov 20, 2025
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)
zimeg commentedon Nov 20, 2025
@sidkurella This is so appreciated! I'll plan to soon investigate this
goimplementation 👾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!
sidkurella commentedon Nov 20, 2025
@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.
zimeg commentedon Nov 21, 2025
@sidkurella I'm finding luck with uploading the following code to a channel:
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...
sidkurella commentedon Nov 21, 2025
@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.
zimeg commentedon Nov 21, 2025
@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 🤖
sidkurella commentedon Nov 21, 2025
@zimeg They're not unreasonably large, our last try was around 1700 bytes or so, used to work fine with the old api
zimeg commentedon Nov 21, 2025
@sidkurella That's within reason for sure! Are these same issues happening with the above snippet I shared or with different files too?
sidkurella commentedon Nov 21, 2025
@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.
sidkurella commentedon Nov 24, 2025
@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)
bensoer commentedon Nov 29, 2025
Hello 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:
mohtakishor commentedon Jan 20, 2026
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"
]
}
}