Errors codes for invalid resumeData with URLSession UploadTask?

I'm coding resumable uploads using iOS 17's URLSession's uploadTask(withResumeData:. This function returns a non-Optional URLSessionUploadTask and does not throw. In cases where the system determines the resumeData is no longer valid, how do I detect that (so I can create a new URLSessionUploadTask from scratch)?

I'm doing this for background uploads, so it's all URLSessionDelegate apis, but what are the failure modes, and what Error types and Codes would we get specially?

Obviously, I expect the resume data is no longer usable or necessary when get a server success i.e. in the 2xx range. Does the resume data also become invalid for other server responses, like 4xx's? or 5xx's?.

I expect the resume data usually shouldn't become invalid when getting URLError's like .networkConnectionLost, since that's like half the point of having the feature in the first place, to resume after the a broken network connection. But I do expect that if the resumeData is invalid, then I should be able to reach the server and get a server response, so in that case what Code would we get?

I'm assuming the system is caching our upload file somewhere, and the resume data somehow makes a reference to it, so does that file get optimized away at some point in time when left untouched, and need us to start a fresh upload? We are also saving the file for potential future re-uploads, until we get certain assurances of completion from our backend, but I am just wondering on which logic branches I need to determine that the resumeData I thought I could use is no longer usable.

Answered by DTS Engineer in 809445022
In cases where the system determines the resumeData is no longer valid, how do I detect that

You don’t need to. I think this quote is salient:

I expect the resume data usually shouldn't become invalid when getting [errors] like .networkConnectionLos

Actually, the resume data is invalid as soon as you use it. Once you start a task with resume data, one of two things will happen:

  • The system is able to resume, in which case it does so.

  • Or it’s not, in which case it’ll start from scratch.

Either way, the resume data is consumed. If the request then fails, that failure will come may or may not come with new resume data, and that’s what you use to retry.

Regarding the file, I recommend that you maintain the file on disk in its original location until the request is completed.

Finally, when testing this it’s good idea to do that testing in a standard session rather than a background session. Background sessions will typically auto resume, so it’s hard to exercise this flow there.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

sorry when writing

then I should be able to reach the server and get a server response

I meant to say

then I shouldn't be able to reach the server and get a server response

In cases where the system determines the resumeData is no longer valid, how do I detect that

You don’t need to. I think this quote is salient:

I expect the resume data usually shouldn't become invalid when getting [errors] like .networkConnectionLos

Actually, the resume data is invalid as soon as you use it. Once you start a task with resume data, one of two things will happen:

  • The system is able to resume, in which case it does so.

  • Or it’s not, in which case it’ll start from scratch.

Either way, the resume data is consumed. If the request then fails, that failure will come may or may not come with new resume data, and that’s what you use to retry.

Regarding the file, I recommend that you maintain the file on disk in its original location until the request is completed.

Finally, when testing this it’s good idea to do that testing in a standard session rather than a background session. Background sessions will typically auto resume, so it’s hard to exercise this flow there.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Eskimo, thanks for your answers. There are several follow up questions I wanted to ask after I did some testing, especially around the concept that the resumeData becomes invalid when I restart the request, for cases where our app crashes after resuming an upload and thus having only the previously saved resume data and not a fresh version.

Unfortunately, when I went to go test some of these scenarios, I discovered that as of last week, CloudFlare's proxy service no longer allows the 104 intermediate response to go through, and thus I'm never getting any resumeData. We've been working with our CloudFlare representative last week and this week, but don't yet have an answer on why that happened, or if they could allow the 104s again. (They never fully worked, because cloudflare always timed out the connection about a minute after the 104s came through, but we were cancelling the upload as soon as we got the 104 so we could get some resume data and save it on disk, and then restarting from resumeData immediately, and that was working fine for months during feature development.)

  • Do you know of any proxy services which do the support Apple's implemented variant of the tusd protocol (i.e. with the intermediate 104 response)?
  • Can Apple somehow influence CloudFlare to support Apple's implemented variant of the tusd protocol? It's been released on iOS devices for over a year. I'm happy to go sit on the sidewalk across the street from their headquarters holding up a sign that says "Support 104s" if it will help.
  • Is there a way to force the resume manually if the device can't get the 104 intermediate response from the server? We're doing PUTs not POSTs and we already have a unique identifier, so from our perspective we could provide the Location header value pre-calculated when we start the upload initially, but I don't know how to synthesize resumeData with that value. It looks like you've carefully neutered NSKeyedArchiver's ability to read the data blob which I could maybe fix, but it also looks like you maybe even encrypted the original request headers in the data blob, so I'm assuming we wouldn't be able to install the correct encryption keys to provide you with a synthesized resumeData?
  • Is there a way to get resume data if the 104 response is final, and not intermediate? In our testing the answer seemed to be 'no'.
Errors codes for invalid resumeData with URLSession UploadTask?
 
 
Q