slackapi / python-slack-sdk

Slack Developer Kit for Python
https://tools.slack.dev/python-slack-sdk/
MIT License
3.85k stars 837 forks source link

files.upload API return {'ok': False, 'error': 'error_creating_file_sync'} #1191

Closed nkj2001 closed 2 years ago

nkj2001 commented 2 years ago

filepath = "test.file" # about 300Mb r = client.files_upload(file=open(filepath, "rb"), channels="MYCHANNELID") print(r.data)

error: slack_sdk.errors.SlackApiError: The request to the Slack API failed. (url: https://www.slack.com/api/files.upload) The server responded with: {'ok': False, 'error': 'error_creating_file_sync'}

what means "error_creating_file_sync" ?????

srajiang commented 2 years ago

@nkj2001 - The error just means that Slack failed to create your file (the sync part just means that it attempted to create your file synchronously). Looking at your example code supplied, open method appears to return a python file object which you are supplying as file. If I were to guess, you should be sending text data instead.

Does this work?

r = client.files_upload(file=open(filepath, "rb").read(), channels="MYCHANNELID")
nkj2001 commented 2 years ago

@srajiang

def files_upload(
        self,
        *,
        file: Optional[Union[str, bytes, IOBase]] = None,
        content: Optional[str] = None,
        filename: Optional[str] = None,
        filetype: Optional[str] = None,
        initial_comment: Optional[str] = None,
        thread_ts: Optional[str] = None,
        title: Optional[str] = None,
        channels: Optional[Union[str, Sequence[str]]] = None,
        **kwargs,
    ) -> SlackResponse:

file is not a problem. And for roughly 150-200 mega files, there's no problem.

app.client.files_upload(file=filepath, channels="CHANNEL_ID")
app.client.files_upload(file=open(filepath, "rb"), channels="CHANNEL_ID")
app.client.files_upload(file=open(filepath, "rb").read(), channels="CHANNEL_ID")
requests.post('https://slack.com/api/files.upload', data=data, files={"file": open(filepath, "rb")}, headers=headers)
requests.post('https://slack.com/api/files.upload', data=data, files={"file": open(filepath, "rb").read()}, headers=headers)
requests.post('https://slack.com/api/files.upload', data=data, files=files, headers=headers)

There are many more methods I've tested. But the problem was not resolved.

srajiang commented 2 years ago

@nkj2001 - I see you closed the issue, so I'm assuming you were able to resolve the error you were seeing 🎉

But for the benefit of others' future reference would you please confirm what you changed?

srajiang commented 2 years ago

@nkj2001 - Alright, thanks for clarifying. So you're not having issues with files 150-200MB, but larger than that you're getting the error back? There is an outstanding bug server-side which we are aware of that might be related to this.

Here's a possible related thread (though I will note in this case the file upload appears to succeed, even though an error is thrown https://github.com/slackapi/python-slack-sdk/issues/1165). It's a bit confusing because different users are reporting different behavior, so thanks for your patience.

Also, can you turn on debug logging on your app and provide the system logs you're getting when you receive your errors?

nkj2001 commented 2 years ago

@srajiang

from slack_sdk import WebClient
client = WebClient(SLACK_USER_TOKEN, timeout=7000)
filepath = "C:\\test.300mb.mp4"
channel_id = "CHANNELID"
r = client.files_upload(file=open(filepath, "rb").read(), channels=channel_id)
print(r.data)

If run the code

    r = client.files_upload(file=open(filepath, "rb").read(), channels="**********")
  File "C:\Python310\lib\site-packages\slack_sdk\web\client.py", line 2995, in files_upload
    return self.api_call("files.upload", files={"file": file}, data=kwargs)
  File "C:\Python310\lib\site-packages\slack_sdk\web\base_client.py", line 145, in api_call
    return self._sync_send(api_url=api_url, req_args=req_args)
  File "C:\Python310\lib\site-packages\slack_sdk\web\base_client.py", line 182, in _sync_send
    return self._urllib_api_call(
  File "C:\Python310\lib\site-packages\slack_sdk\web\base_client.py", line 324, in _urllib_api_call
    ).validate()
  File "C:\Python310\lib\site-packages\slack_sdk\web\slack_response.py", line 205, in validate
    raise e.SlackApiError(message=msg, response=self)
slack_sdk.errors.SlackApiError: The request to the Slack API failed. (url: https://www.slack.com/api/files.upload)
The server responded with: {'ok': False, 'error': 'error_creating_file_sync'}

An error occurs when the file exceeds 230-300 megabytes. Socket mode and HTTP mode are the same. Using slack_sdk, slack_bolt or calling directly with requests or equivalent. The server always returned the same result when sending the file using all available methods.

   filepath = "C:\\test.300MB.mp4"
   C_ID = "CHANNELID"
    with open(filepath, "rb") as f:
        headers={"Authorization": "Bearer {}".format(SLACK_BOT_TOKEN)}
        r = requests.post(
                    'https://slack.com/api/files.upload', 
                    data={"title": "TEST", "channels": C_ID}, 
                    files={"file": f}, 
                    headers=headers
        )
        print(r.text)

If I send a file using the requests library

{"ok":false,"error":"error_creating_file_sync"}

requests didn't throw any errors and the server just returns this status.

srajiang commented 2 years ago

Okay @nkj2001 - Thanks for providing the additional detail, I am confident that this is server-side issue and not an issue with the SDK tooling. I will raise the isue (again) to those internal teams about the behavior you're seeing to get this on their radar and mark this issue with a flag to keep it open until we find a resolution.

nkj2001 commented 2 years ago

@srajiang Thank you for your interest.

willAIZ commented 2 years ago

Hi, any update on this by any chance? I see the exact same behavior, 125MB file upload works correctly, but 250MB upload encounters the

{'ok': False, 'error': 'error_creating_file_sync'}

Our code issues several retries with some exponential backoff in between, but each retry encounters the same issue.

seratch commented 2 years ago

Hi all, let me share some updates on this issue.

Firstly, sincere apologies for taking a long time to resolve this issue on the Slack platform side. We do understand that this issue has been critical for many people.

As a solution, we just released v3.19.0, which includes a new method named WebClient#files_upload_v2(). This new method is much stabler and is mostly compatible with the existing files_upload() method. Please migrate to the new method if your app is affected by the server-side performance issue described here. Here is an example code demonstrating how to use the v2 method:

response = client.files_upload_v2(
    file="./logo.png",
    title="New company logo",
    # Note that channels still works but going with channel="C12345" is recommended
    # channels=["C111", "C222"] is no longer supported. In this case, an exception can be thrown 
    channels=["C12345"],
    initial_comment="Here is the latest version of our new company logo :wave:",
)

The new method eliminates the timeouts. In addition, it enables 3rd party app developers to upload multiple files like humans do in Slack clients. This feature addition can be useful for many use cases. Here is a simple example code:

response = client.files_upload_v2(
    file_uploads=[
        {
            "file": "./logo.png",
            "title": "New company logo",
        },
        {
            "content": "Minutes ....",
            "filename": "team-meeting-minutes-2022-03-01.md",
            "title": "Team meeting minutes (2022-03-01)",
        },
    ],
    channel="C12345",
    initial_comment="Here is the latest version of our new company logo :wave:",
)
response.get("files")  # returns the full metadata of all the uploaded files

Please refer to the release notes for more details: https://github.com/slackapi/python-slack-sdk/releases/tag/v3.19.0

elongl commented 1 year ago

Worth mentioning that unlike the previous function (files_upload), the new function (files_upload_v2) expects and supports only a channel ID and not a channel name.

elongl commented 1 year ago

How come files:read is also needed even though it successfully uploads the file without it?

seratch commented 1 year ago

@elongl For better compatibility with legacy files.upload, the v2 method calls files.info to fetch the uploaded files' full metadata. We know that some people do not want to have files:read scope for the purpose, so in the upcoming patch release, you can pass request_file_info=False to the method to disable the file metadata loading part. Refer to https://github.com/slackapi/python-slack-sdk/issues/1277 and https://github.com/slackapi/python-slack-sdk/pull/1282 for more details.

elongl commented 1 year ago

Thanks a lot for the explanation. I'd appreciate it if you could explain, if files.upload previously returned the files' full metadata without the files:read scope. Why is it no longer possible now?

seratch commented 1 year ago

@elongl It is due to Slack server-side reasons and we won't change it, unfortunately. The underlying files.completeUploadExternal API method, which is part of files_upload_v2, works with only files:write scope, but it returns only file's ID and title unlike the legacy one. To mitigate developers' surprise here, the v2 method fetches other properties using files:read.

By the way, this issue is already closed. If you have further questions, please start a new question issue for it.

Gluzdovska13 commented 1 year ago

Hello i have no exactly problem like that, but similar. I have cicle of files upload, and when files in my cicle is too big only first file was loaded and gave me mistake in responce, in thi case i use something like that, mayby it can help someone:

client_slack = AsyncWebClient(token=os.environ.get("SLACK_BOT_TOKEN"))
for df in dfs:
        buff = BytesIO()
        df.to_csv(buff, index=False)
        buff.seek(0)
        try:
            await client_slack.files_upload(
                file=buff,
                channels=channel_id,
                filename="some name",
                filetype='csv')
        except Exception as err:
            print(f"{err} error slack")

With exaption all files loaded, no limits for size.

vesuvius13 commented 1 year ago

I'm getting an error while using client.files_upload_v2 method when I use a dataframe in content to be sent as a csv file.

The code:- client.files_upload_v2( channel = "Channel ID", initial_comment = "Have fun analysing my csv file! :stuck_out_tongue:", filename = "filename.csv", content = df)

This is the error:-

/databricks/python/lib/python3.8/site-packages/slack_sdk/web/client.py in files_upload_v2(self, filename, file, content, title, alt_txt, snippet_type, file_uploads, channel, initial_comment, thread_ts, request_file_info, **kwargs)
   3092                 files.append(_to_v2_file_upload_item(f))
   3093         else:
-> 3094             f = _to_v2_file_upload_item(
   3095                 {
   3096                     "filename": filename,

/databricks/python/lib/python3.8/site-packages/slack_sdk/web/internal_utils.py in _to_v2_file_upload_item(upload_file)
    332             data = content
    333         else:
--> 334             raise SlackRequestError("content for file upload must be 'str' (UTF-8 encoded) or 'bytes' (for data)")
    335 
    336     filename = upload_file.get("filename")

SlackRequestError: content for file upload must be 'str' (UTF-8 encoded) or 'bytes' (for data)
seratch commented 1 year ago

@vesuvius13

content for file upload must be 'str' (UTF-8 encoded) or 'bytes' (for data)

As this error message indicates, a dataframe object is not supported for the content parameter. Please convert the data to either str or byte array before passing it.

vesuvius13 commented 1 year ago

@vesuvius13

content for file upload must be 'str' (UTF-8 encoded) or 'bytes' (for data)

As this error message indicates, a dataframe object is not supported for the content parameter. Please convert the data to either str or byte array before passing it.

But it was supported under files_upload right?

seratch commented 1 year ago

@vesuvius13 Thanks for sharing this. Indeed, the validation did not exist in the legacy one. But the legacy one does not intentionally support the data structure (at least we don't have any unit tests for it). I hear you on the frustration but please convert the data to any of the compatible ones when migrating to v2.