URLSessionUploadTask getting automatically cancelled instantly

I'm having this weird issue in which a newly created URLSessionUploadTask gets cancelled instantly. I'm not sure if it's a bug with the current beta of Xcode 8.


I'm trying to build a Framework project.


I suspect it might be a bug because the code I'm about to post ran fine exactly once. No changes were made to it afterwards and then it simply stopped working. Yes, it literally ran once, and then it stopped working. I will post the error near the end.


I will post the code below, but first I will summarize how the logic here works.


My test, or user-exposed API (IE for use in Playgrounds or directly on apps), calls the `authorize` method. This `authorize` method will in turn call `buildPOSTTask`, which will construct a valid URL and return a `URLSessionUploadTask` to be used by the `authorize` method.


With that said, the code is below:


The session:



internal let urlSession = URLSession(configuration: .default)



Function to create an upload task:



    internal func buildPOSTTask(onURLSession urlSession: URLSession, appendingPath path: String, withPostParameters postParams: [String : String]?, getParameters getParams: [String : String]?, httpHeaders: [String : String]?, completionHandler completion: URLSessionUploadTaskCompletionHandler) -> URLSessionUploadTask {
        let fullURL: URL
        if let gets = getParams {
            fullURL = buildURL(appendingPath: path, withGetParameters: gets)
        } else {
            fullURL = URL(string: path, relativeTo: baseURL)!
        }
      
        var request = URLRequest(url: fullURL)
        request.httpMethod = "POST"
      
        var postParameters: Data? = nil
      
        if let posts = postParams {
            do {
                postParameters = try JSONSerialization.data(withJSONObject: posts, options: [])
            } catch let error as NSError {
                fatalError("[\(#function) \(#line)]: Could not build POST task: \(error.localizedDescription)")
            }
        }
      
        let postTask = urlSession.uploadTask(with: request, from: postParameters, completionHandler: completion)
        return postTask
    }


The authentication function, which uses a task created by the above function (I have removed a lot of irrelevant code):



        public func authorize(withCode code: String?, completion: AccessTokenExchangeCompletionHandler) {
  
    // I hav
            let obtainTokenTask = buildPOSTTask(onURLSession: self.urlSession, appendingPath: "auth/access_token", withPostParameters: nil, getParameters: body, httpHeaders: nil) { (data, response, error) in
                if let err = error {
                    completion(error: err)
                } else {
                    print("Response is \(response)")
                    completion(error: nil)
                }
            }
          
            obtainTokenTask.resume()
        }


I caught this error in a test:



    let testUser = Anilist(grantType: grant, name: "Test Session")
  
    let exp = expectation(withDescription: "Waiting for authorization")
  
    testUser.authorize(withCode: "a valid code") { (error) in
        if let er = error {
            XCTFail("Authentication error: \(er.localizedDescription)")
        }
        exp.fulfill()
    }
    self.waitForExpectations(withTimeout: 5) { (err) in
        if let error = err {
            XCTFail(error.localizedDescription)
        }
    }


It always fails instantly with this error:



Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLKey=https://anilist.co/api/auth/access_token?client_secret=REMOVED&grant_type=authorization_code&redirect_uri=genericwebsitethatshouldntexist.bo&client_id=ibanez-hod6w&code=REMOVED,
NSLocalizedDescription=cancelled,
NSErrorFailingURLStringKey=https://anilist.co/api/auth/access_token?client_secret=REMOVED&grant_type=authorization_code&redirect_uri=genericwebsitethatshouldntexist.bo&client_id=ibanez-hod6w&code=REMOVED}



Here's a few things to keep in mind:


- The URL used by the session is valid.

- All credentials are valid.

- It fails *instantly* with a "cancelled" error, that simply did not happen before. I am not cancelling the task anywhere, so it's being cancelled by the system. It doesn't look like it has time to hit the network, because the test fails as soon as it is started.

- **It also fails on Playgrounds with indefinite execution enabled**. This is not limited to my tests.


Here's a list of things I have tried:


- Because I suspect this is a bug, I first tried to clean my project, delete derived data, and reset all simulators. None of them worked.

- Even went as far restarting my Mac...

- Under the small suspicion that the upload task was getting deallocated due to it not having any strong pointers, and in turn calling `cancel`, I also rewrote `authorize` to return the task created by `buildPOSTTask` and assigned it to a variable in my test. The task was still getting cancelled.


I'm out of ideas of what to try. The generated logs don't seem to have any useful info.


(If anyone is willing to go above and beyond to help me, I can upload the whole project here, since it will be open source anyway. The project is really small currently, consisting of three small Swift files and one test file).

Accepted Reply

Sorry for reviving this, but I saw my question here after registering to the new forums, and I thought I could update based on my findings.

The from parameter of uploadTask(with:from:completionHandler) cannot be nil. While the signature of the method does mark from as a Data?, the task gets automatically cancelled when it is missing/nil.

I have had a radar on this for a few years (FB5986524), but I never got any response.

Replies

It fails instantly with a "cancelled" error, that simply did not happen before.

Yeah, that’s weird.

Let’s try something simple. Here’s a snippet of code:

let session = URLSession(configuration: .default)

@IBAction func testAction(_ sender: AnyObject) {
    var request = URLRequest(url: URL(string: "https://httpbin.org/post")!)
    request.cachePolicy = .reloadIgnoringLocalCacheData
    request.httpMethod = "POST"
    let body = "Hello Cruel World!".data(using: .utf8)
    let task = session.uploadTask(with: request, from: body) { (data, response, error) in
        if let error = error {
            NSLog("error %@", error)
        } else {
            let response = response as! HTTPURLResponse
            let data = data!
            NSLog("success %d", response.statusCode)
            if response.statusCode == 200 {

                NSLog(">>%@<<", String(data: data, encoding: .utf8) ?? "")
            }
        }
    }
    task.resume()
}

I added this to a new project, created from the Single View Application template, wired a button up to

testAction(_:)
, and ran in Xcode 8.0b3. It successfully got a response from the server. Please try that at your end and let us know what you see.

If this code works and your code fails, there’s something specific about your server (or your environment) that’s causing the problem.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
Sorry for reviving this, but I saw my question here after registering to the new forums, and I thought I could update based on my findings.

The from parameter of uploadTask(with:from:completionHandler) cannot be nil. While the signature of the method does mark from as a Data?, the task gets automatically cancelled when it is missing/nil.

I have had a radar on this for a few years (FB5986524), but I never got any response.