Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When uploading a DriveItem, an error occurs with the message: '[item] Read called with an open stream or textreader. Please close any open streams or text'readers before calling Read.' #276

Closed
hide212131 opened this issue Jul 26, 2023 · 5 comments

Comments

@hide212131
Copy link

hide212131 commented Jul 26, 2023

I am trying to upload content to SharePoint.
I can handle authentication, obtain Drive information, and download content successfully.
However, I cannot upload content. I encountered the following error:

client = GraphServiceClient(credentials=credential, scopes=scopes)
drive_req = client.drives.by_drive_id(DRIVE_ID)
...
request_body = DriveItem()
request_body.name = 'a.txt'
request_body.file = File()
request_body.content = b'abcde'
result = await drive_req.items.by_drive_item_id('root').children.post(body=request_body)

msgraph.generated.models.o_data_errors.o_data_error.ODataError: {"message": null, "response_status_code": 400,
...
"message": "[item] Read called with an open stream or textreader. Please close any open streams or text readers before calling Read."

I attempted to pass a stream and made the necessary modifications as follows. The error no longer occurs; however, the uploaded file has a size of 0 bytes.

request_body.content = io.BytesIO(b'abcde')

Could the issue be due to incorrect usage of the API?

@vdimov-gcmlp
Copy link

Did you resolve this issue?

@shinkawk
Copy link

Hi @hide212131 @vdimov-gcmlp

After tinkering for a several days, I found the following code as a workaround:

# Create an empty file called a.txt via Post API
request_body = DriveItem()
request_body.name = 'a.txt'
request_body.file = File()
result = await drive_req.items.by_drive_item_id('root').children.post(body=request_body)

# Put actual data using Put API
file_id = result.id
content = b'abcde' # Load your actual data here
await drive_req.items.by_drive_item_id(file_id).content.put(body=content)

So instead of trying to put bytes data using POST, you can upload data with PUT after creating an empty DriveItem.

Hope this helps!

@vdimov-gcmlp
Copy link

@shinkawk, thank you for the example. I was able to successfully upload a file another way using the example below, but that has downsides (it allows to overwrite existing files, creating a version of the previous file, without providing additional request params.

await client.drives.by_drive_id(drive_id).items.by_drive_item_id(parent_id).children.by_drive_item_id1("file_name.txt").content.put(b'abcde')

Given MSGraph documentation, both ways should work for files <4MB. Anything larger would necessitate creating an upload session which is also not documented. If anyone has a sample of creating a session to upload larger files that will be greatly appreciated.

@paulschmeida
Copy link

The method above works for files up to 250mb, just tested it.

@andrueastman
Copy link
Member

Closing this for now. Correct usage of the API is to use a PUT request to the /content endpoint

https://learn.microsoft.com/en-us/graph/api/driveitem-put-content?view=graph-rest-1.0&tabs=http

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants