OneDrive / onedrive-api-docs

Official documentation for the OneDrive API
MIT License
454 stars 230 forks source link

"ItemNotFound" when uploading file #1132

Closed tipa closed 1 year ago

tipa commented 5 years ago

using Graph.NET Nuget package 1.17.0 in my UWP app

Expected behavior

I am able to upload a file to OneDrive (into the apps app folder).

Actual behavior

An exception is thrown (see below) - but only sometimes! I feel like it mostly (or only) happens the first time the app tries to upload something to its (newly created) app folder. It usually (but not always!) succeeds on a second attempt.

Microsoft.Graph.ServiceException: Code: itemNotFoundMessage: Item does not existInner error at Microsoft.Graph.HttpProvider.d19.MoveNext() + 0x5ac--- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x21 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0x5c at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task) + 0x44 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task) + 0x1c at Microsoft.Graph.BaseRequest.d36.MoveNext() + 0x475--- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x21 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0x5c at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task) + 0x44 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task) + 0x1c at Microsoft.Graph.BaseRequest.d32`1.MoveNext() + 0x12f--- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x21 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0x5c at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task) + 0x44 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task) + 0x1c at Diarium.OneDriveHelper.d15.MoveNext() + 0x2ad--- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x21 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0x5c at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task) + 0x44 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task) + 0x1c at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult() + 0xb at Diarium.OneDriveHelper.d__1.MoveNext() + 0x150e

Steps to reproduce the behavior

static async Task UploadFile(GraphServiceClient graphClient, string filePath, MemoryStream stream)
{
    if (stream.Length > 4194304)
    {
        var session = await graphClient.Drive.Special.AppRoot.ItemWithPath(filePath).CreateUploadSession().Request().PostAsync();
        await new ChunkedUploadProvider(session, graphClient, stream).UploadAsync();
    }
    else
    {
        await graphClient.Drive.Special.AppRoot.ItemWithPath(filePath).Content.Request().PutAsync<DriveItem>(stream);
    }
}

Issue occured on both the "beta" and "v1.0" endpoint

This issue was also raised here: https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/385

zachzi commented 3 years ago

@raydixon / @tipa thanks for your responses! Unfortunately, the logging really only provides limited information about the request, all of which we already know (mainly, the error being thrown). A full trace, like I mentioned above, gives us much more detail about the execution of the request. @raydixon: does it repro if you just delete the "Apps" folder? Tried this a bit myself and haven't been able to get a repro. We suspect this is caused by some kind of intermittent race condition dealing with creating the app root folder if it doesn't already exist.

All that said, I think we have a workaround for you: before a user even tries to upload a document to your app's folder, could you make a GET request to: https://graph.microsoft.com/v1.0/me/drive/special/approot? This will provision your app's root folder if it doesn't already exist, and you should receive a 200 response. Afterwards, uploading to that folder should work consistently.

raydixon commented 3 years ago

@zachzi I haven't tried deleting the Apps folder completely. I'll give that a try tomorrow and report back here.

zachzi commented 3 years ago

We are still investigating the underlying issue, but hopefully that workaround can help your app avoid this error.

tipa commented 3 years ago

Unfortunately I am not able to reproduce the problem with my OneDrive account, therefore I cannot produce a trace. I will ask my users to get such a trace the next time they are mailing me.

All that said, I think we have a workaround for you: before a user even tries to upload a document to your app's folder, could you make a GET request to: https://graph.microsoft.com/v1.0/me/drive/special/approot?

In my app I am already making a GET request to https://graph.microsoft.com/v1.0/me/drive/special/approot:/data_v4.wh:?$select=fileSystemInfo,size before starting any upload

zachzi commented 3 years ago

@tipa interesting - is that right before starting the upload? I'm wondering if there's any chance the user could have deleted the approot folder, so it needed to be recreated?

zachzi commented 3 years ago

@tipa so I've confirmed the behavior here: if you make a GET request to a file in that app folder that doesn't exist, and the app folder itself doesn't exist, it will not be created. Instead, could you change it to just access the app folder itself (GET https://graph.microsoft.com/v1.0/me/drive/special/approot)?

The safest approach would be to always call that before starting the upload, but if you want to avoid making extra requests, an alternative would be to call that after the upload fails with a 404.

tipa commented 3 years ago

I always make that GET request to that file right before trying to upload / overwrite (or download, depending on the fileSystemInfo) that file. If it returns 404, then that error indicates to me that the file is not present and needs to be uploaded first.

I will now change the code that it will also make a GET request to the app root folder when the GET on the file returns 404. I think this problem only occurs when the folder has not been created yet so it should only happen in that case. But I will also add logging to ensure this assumption is correct. Will report back as soon as I upload an update containing this change and could get some new data in.

Pseudo code:

DriveItem file;
try {
  file = GET drive/special/approot:/data_v4.wh
} catch (404 ItemNotFound) {
  GET drive/special/approot:/    // <---- I will add this line
}

if (file == null) {
  PUT drive/special/approot:/data_v4.wh
} else if (file.Date > DateTime.Now) {
  GET drive/special/approot:/data_v4.wh:/content
}
raydixon commented 3 years ago

@zachzi I just tried deleting the Apps folder completely and WorkingHours (version 2.6.7.0) just re-created it, without any problem. @tipa whatever you've implemented in the latest version and/or the troubleshooting I've done put me in a state now where I can't repro the issue.

zachzi commented 3 years ago

Thanks @tipa / @raydixon - please let me know if you are still encountering errors after that change.

tipa commented 3 years ago

@zachzi I updated my apps with the change and from what I can see now and the last couple of days, adding that GET request as shown in my Pseudocode above fixed the issue / created the app folder - GREAT! So only thing I would ask for now is that OneDrive could create the app folder automatically when doing a file upload to a (non-existing) app folder. Most of the times (for 99% of the users) this already happens, but 100% would be better :D Then I could remove one more workaround in my OneDrive logic :)

zachzi commented 3 years ago

@tipa thanks for confirming! Agreed about fixing the underlying bug, we're still tracking this on our backlog.

patrick-rodgers commented 1 year ago

As part of a repository clean up effort we are closing older issues. If this issue remains, please: open a new issue, reference this issue, and provide any additional details that may help in resolution. Thank you for your understanding as we work to improve our responsiveness.