Search code examples
iosswiftcloudkit

cloudkit error no authToken received for asset


Why do I get this error when I run the following code? :

"Internal Error" (1/1000); "No authToken received for asset"

I think it has something to do with the setObject code in the last line.

let documentsDirectoryPath:NSString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
var imageURL: URL!

let imageData = UIImageJPEGRepresentation(self.newImage, 1.0)
let path:String = documentsDirectoryPath.appendingPathComponent(self.newImage.description)
try? UIImageJPEGRepresentation(self.newImage, 1.0)!.write(to: URL(fileURLWithPath: path), options: [.atomicWrite])
imageURL = URL(fileURLWithPath: path)
try? imageData?.write(to: imageURL, options: [.atomicWrite])

let imageAsset:CKAsset? = CKAsset(fileURL: URL(fileURLWithPath: path))


curImages = record["Images"] as! [CKAsset]
curImages.append(imageAsset!)

print("saving image")
record.setObject(curImages as CKRecordValue?, forKey: "Images")

Solution

  • I've encountered this, too. It appears to be a bug in cloudkit, and--from what I can tell--it happens when you try to re-use any part of the "asset creation chain."

    In other words, you have some initial data, you create an image from that data, you write it to a file, you load that file into a CKAsset, then you load the CKAsset into the CKRecrod. In my experiments, if you re-use any of those components... or if they just happen to be the same (that is, you create an image, then you happen to create a new-but-identical image later) you'll see this error.

    For example, the following code reliably recreates the "no auth token" error when saving a record. All it does is create an array of assets and places it into the record:

    for (int i = 0; i <= maxPlayers; i++)
    {
        int tempVal = 0xf;
        NSData *tempData = [[NSData alloc] initWithBytes:&tempVal length:sizeof(tempVal)];
        NSString *tempDataFilepath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"temp%d.dat",i]];
        [tempData writeToFile:tempDataFilepath atomically:YES];
        NSURL *tempDataURL = [NSURL fileURLWithPath:tempDataFilepath];
        someArray[i] = [[CKAsset alloc] initWithFileURL:tempDataURL ];
    }
    
    someRecord[SOME_FIELD_NAME] = someArray; 
    

    Simply changing the third line to:

    int tempVal = i; //force the temp value to be different every time
    

    Completely solves the error.

    Furthermore, this error occurs even when I tried to use a value in a different CKAsset **that was already used in a prior CKAsset For example, using int tempVal = 0xf in the first asset, then using int secondTempVal = 0xf in another CKAsset also produces the "no auth token" error.

    In my case, I was able to force the asset value to always be a unique value, and completely solved the problem. In your case, I suggest the following possible work arounds:

    1. Check if you're using identical images for your assets. If you are, try slightly modifying the images for each new CKAsset.
    2. If you must re-use identical images, try saving the record after you set each asset. I do not know if that will solve the issue, and it certainly increases your network traffic. But it's worth an experiment to see if it helps.
    3. In this question Saving CKAsset to CKRecord in CloudKit produces error: "No authToken received for asset" the OP was able to create separate copies of the image file that ultimately solved the problem.
    4. Open a bug with Apple. I didn't bother doing this, as I've grown jaded watching similar bug reports sit open for years without attention. But who knows, you might have better luck.