CloudKit Batch Error: Previous Error in Atomic Zone - cloudkit

I am attempting to save a CKRecord using a CKModifyRecordsOperation and every time I try it, I get this initial error:
["CKErrorDescription": Failed to modify some records,
"CKPartialErrors": {
"CKRecordID: 0x60c000034000; recordName=ABC, zoneID=workspaceZone:DEF" = "CKError 0x60c000257340: \"Batch Request Failed\" (22/2024); \"Record CKRecordID: 0x7fb2f6998a60; recordName=ABC, zoneID=workspaceZone:DEF will not be saved because of previous error in atomic zone\"";
},
"NSDebugDescription": CKInternalErrorDomain: 1011, "NSUnderlyingError": CKError 0x60c000248af0: "Partial Failure" (1011); "Failed to modify some records"; partial errors: {
... 1 "Batch Request Failed" CKError's omited ...
},
"NSLocalizedDescription": Failed to modify some records]
I then parse the individual errors of the batch like this:
if let errorItems = error.partialErrorsByItemID {
for item in errorItems{
if let itemError = item.value as? CKError{
print("::: Individual Error in Batch :::")
print(itemError)
print(":::::")
}
}
}
But all the individual error says is:
CKError(_nsError: CKError 0x60c000257340: "Batch Request Failed" (22/2024); "Record CKRecordID: 0x7fb2f6998a60; recordName=GHI, zoneID=workspaceZone:JKL will not be saved because of previous error in atomic zone")
The CloudKit server log just says it's a BAD_REQUEST which isn't very helpful either.
Is there a way to get more details as to what's wrong with my record?

This just means one of your requests failed. You're doing a batch request with one or more requests. If one fails, CloudKit fails all of the requests to keep things atomic.
So, you should subscribe to errors on each record with perRecordCompletionBlock. Then, you can see which record is failing and why. You should print out the userInfo dictionary of the error for more detailed information.

Related

Solana metaplex auction fails in ValidateSafetyDepositBoxV2 instruction with "Supplied an invalid creator index to empty payment account"

I'm porting metaplex auction-house to Flutter mobile.
When creating auction with instant sale price of 0.1 wrapped sol, I have encountered the following error at the stage of ValidateSafetyDepositBoxV2 instruction.
The error was "Supplied an invalid creator index to empty payment account" and there is only one point where this message can be printed is Rust's process_empty_payment_account().
The most weird thing is that process_empty_payment_account function is called only from EmptyPaymentAccount instruction and my program didn't call it.
any idea what's happening?
Actual error log:
I/flutter ( 2718): {accounts: null, err: {InstructionError: [0, {Custom: 63}]}, logs: [Program p1exdMJcjVao65QdewkaZRUnU6VPSXhus9n2GzWfh98 invoke [1], Program log: Instruction: Validate Safety Deposit Box V2, Program log: Supplied an invalid creator index to empty payment account, Program p1exdMJcjVao65QdewkaZRUnU6VPSXhus9n2GzWfh98 consumed 11849 of 200000 compute units, Program p1exdMJcjVao65QdewkaZRUnU6VPSXhus9n2GzWfh98 failed: custom program error: 0x3f], unitsConsumed: 0}
I found the reason why that error was given after deploying a new program with some logs to the rust program. It was that I passed the wrong value for the metadata's address as the 4th account.
pub fn process_validate_safety_deposit_box_v2<'a>(
program_id: &'a Pubkey,
accounts: &'a [AccountInfo<'a>],
safety_deposit_config: SafetyDepositConfig,
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let safety_deposit_config_info = next_account_info(account_info_iter)?;
let auction_token_tracker_info = next_account_info(account_info_iter)?;
let mut auction_manager_info = next_account_info(account_info_iter)?;
*let metadata_info = next_account_info(account_info_iter)?;*
....
So, the program failed at Metadata::try_from_slice_checked and returns error of InvalidCreatorIndex at the following code.
impl Metadata {
pub fn from_account_info(a: &AccountInfo) -> Result<Metadata, ProgramError> {
let md: Metadata =
try_from_slice_checked(&a.data.borrow_mut(), Key::MetadataV1, MAX_METADATA_LEN)?;
Ok(md)
}
}
It's a pity that the code didn't give a more elaborate error.

google-cloud/firestore: Error: 4 DEADLINE_EXCEEDED: Deadline Exceeded while creating document

I'm trying to create document using following code and getting "Error: 4 DEADLINE_EXCEEDED: Deadline Exceeded" while running ref.set() function. I'm using "ws" and "fastify" and there are few number(100-150) of sockets are getting handled. This error is not coming in initial days. Its coming up after 4-5 days after restarting process on server.
create: async (id) => {
//store socket
return await socketRef.doc(id).set({ id: id, connectedAt: fastify.fsTimestamp() })
},
socketRef = Firestore collection reference
Following is complete error. Not understanding why this happening.
{ Error: 4 DEADLINE_EXCEEDED: Deadline Exceeded
at Object.exports.createStatusError (/root/airsniper.api/node_modules/grpc/src/common.js:87:15)
at Object.onReceiveStatus (/root/airsniper.api/node_modules/grpc/src/client_interceptors.js:1188:28)
at InterceptingListener._callNext (/root/airsniper.api/node_modules/grpc/src/client_interceptors.js:564:42)
at InterceptingListener.onReceiveStatus (/root/airsniper.api/node_modules/grpc/src/client_interceptors.js:614:8)
at callback (/root/airsniper.api/node_modules/grpc/src/client_interceptors.js:841:24)
code: 4,
metadata: Metadata { _internal_repr: {} },
details: 'Deadline Exceeded' }
As #Ashish mentioned, the answer can be found in another thread and is as follows:
Deadline Exceeded error occurs due to Firestore limit of Maximum write rate to a document - 1 per second.

Swift Core Data Query Generation Sqlite error code 769 ( sqlite3_snapshot_open failed )

I'm using core data query generation,for each read on view context data i do the following
pin context
read (fetch request)
unpin context
Everything is working correctly as expected, but sometimes I get the following error:
error: SQLCore dispatchRequest: exception handling request: , sqlite3_snapshot_open failed with userInfo of {
NSSQLiteErrorDomain = 769;
}
CoreData: error: SQLCore dispatchRequest: exception handling request: , sqlite3_snapshot_open failed with userInfo of {
NSSQLiteErrorDomain = 769;
}
Below the code to pin/unpin the context:
// MARK: Query generation
func pinContext() {
do {
context.reset()
try context.setQueryGenerationFrom(NSQueryGenerationToken.current)
} catch {
fatalError("Context pinning:\(error)")
}
}
func unpinContext() {
do {
try context.setQueryGenerationFrom(nil)
} catch {
fatalError("Context unpinning:\(error)")
}
}
sqlite.org web site for error code (769) SQLITE_ERROR_SNAPSHOT states:
The SQLITE_ERROR_SNAPSHOT result code might be returned when attempting to start a read transaction on an historical version of the database by using the sqlite3_snapshot_open() interface. If the historical snapshot is no longer available, then the read transaction will fail with the SQLITE_ERROR_SNAPSHOT. This error code is only possible if SQLite is compiled with -DSQLITE_ENABLE_SNAPSHOT.
Now, how may I handle or prevent this error in Core data?
bgCTX = container.newBackgroundContext()
bgCTX.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
bgCTX.automaticallyMergesChangesFromParent = true
try bgCTX.setQueryGenerationFrom(NSQueryGenerationToken.current)
Do you have automaticallyMergesChangesFromParent set to true? If so, that seems to cause issues. According to a comment in NSManagedObjectContext:
/* Whether the context automatically merges changes saved to its coordinator or
parent context. Setting this property to YES when the context is pinned to a non-
current query generation is not supported.
*/
#available(iOS 10.0, *)
open var automaticallyMergesChangesFromParent: Bool
If your context is pinned to the "current" query generation token, then it shouldn't be an issue. However, that query generation token could quickly become stale (non-current) if you are saving data to the store on other contexts. As soon as it tries to merge changes from the parent, it gets into an unknown state, which causes this error/crash.
From what I can tell, setting automaticallyMergesChangesFromParent to false when pinning a context is the safest route. Then you can set it to true again when unpinning.
I wish Apple would update their documentation with this, but instead we have to find out about it in a comment in their code.

Unable to properly handle errors

I have found the reason why my application isn't behaving the way I would like it to but I don't know how to resolve the issue. To summarise, my application has a custom error handler which gets invoked if there is an error. The error handler sends json messages. But in one application startup error scenario (Future fails), I want to Redirect the user to homepage instead of sending a json message.but it doesn't happen because the custom error handler sends json message before I can send a Redirect from Future's recover.
One feature of the application is signup verification. The user clicks on a url which has a token. When the url is clicked, verifyUser Action is called. It does some checks (using database queries using Futures) and depending on the success or failure, it sends Redirect with signup=success or signup=error attribute (not failure here is decided based on whether something exists in the database or not). However, if the Future fails (I queried a wrong field which is not part of database's schema), I want to Redirect again but it doesn't work as the custom error handler gets invoked before recover. How could I make my application Redirect?
val result:Future[Result] = for{tokenOption:Option[UserToken] <- userTokenRepo.findOne(UserTokenKey(UUID.fromString(token))) //generator 1 - get token from database
userOption:Option[User] <- if (tokenOption.isDefined) userRepo.findOne(tokenOption.get.userKeys) else Future.successful(None) //generator2. found token, look for corresponding user to which the token belongs
modifiedUser:Option[User] <- if (userOption.isDefined) confirmSignupforUser(userOption.get) else Future.successful(None) //generator 3. found user and token. Update profile
deletedToken:Option[UserTokenKey] <- if(modifiedUser.isDefined) userTokenRepo.delete(UserTokenKey(UUID.fromString(token))) else Future.successful(None)
}
yield { //check if we have user and token and modified user here. If any is missing, return error else success
println("db query results tokenOption: "+tokenOption+", userOption: "+userOption+" : modifiedUserOption: "+modifiedUser+", deletedToken: "+deletedToken)
if(tokenOption.isDefined && userOption.isDefined && modifiedUser.isDefined && deletedToken.isDefined)
Redirect("http://localhost:9000/home"+";signup=success")//TODOM - pick from config
else
/*TODOM - when redirecting with error, can provide additional info why sign up failed*/
if(tokenOption.isEmpty)
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
else if(userOption.isEmpty)
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
else if(modifiedUser.isEmpty)
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
else //this shouldn't happen. Unexpected
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
}
result.recover { case x => {
println("Future failed in validateUserSession. Recovering. Returning Internal Server Error" + x)
//before this Redirect, the custom error handler sends json response
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
}
}
Custom error handler
class CustomHttpErrorHandler extends HttpErrorHandler {
def onClientError(request: RequestHeader, statusCode: Int, message: String) = {
println("client error: request "+request+", statusCode: "+statusCode+", message:"+message)
Future.successful(
Status(statusCode)(Json.toJson(JsonResultError(message)))
)
}
def onServerError(request: RequestHeader, exception: Throwable) = {
println("server error: request: "+request+", exception: "+exception.getMessage)
Future.successful(
InternalServerError(Json.toJson(JsonResultError(exception.getMessage)))
)
}
}
I am able to verify the isse as I see two debugs (one from custom error handler and other from recover)
server error: request: GET /ws/users/signup/312c9eaf-f27b-43c7-8dac-445a628c3be8, exception: bucket_id is not a column defined in this metadata
Future failed in validateUserSession. Recovering. Returning Internal Server Errorjava.lang.IllegalArgumentException: bucket_id is not a column defined in this metadata
I could try to check based on the exception received in custom error handler but I think it is too generic and might not be a good design approach.
It is possible that the error is happening before the Future is created so the code is throwing an exception that is handled by the default handler rather than being caught by the Future.
Specifically, the expression
userTokenRepo.findOne(UserTokenKey(UUID.fromString(token)))
is evaluated in the current thread, so any exception in this code will not be caught and will invoke the default error handler.
The solution is to compute this in a Try and process the error immediately if there is one.
This is what it might look like:
for {
tokenKey <- Future.fromTry(Try(UserTokenKey(UUID.fromString(token))))
tokenOption <- userTokenRepo.findOne(tokenKey)
userOption <- tokenOption.fold(Future.successful)(userRepo.findOne(_.userKeys)) //generator2. found token, look for corresponding user to which the token belongs
modifiedUser <- userOption.fold(Future.successful)(confirmSignupforUser) //generator 3. found user and token. Update profile
...
Any exception in this code will result in a failed Future which your recover code will handle.

Swift Core Data: Data not persisting between session. context.save() works for the session only

I am facing a strange issue with CoreData. I am starting a operation to fill initial data in a table. I am starting the operation in applicationDidBecomeActive.
// Creating child context
let context = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
let delegate = UIApplication.sharedApplication().delegate as! AppDelegate
context.parentContext = delegate.managedObjectContext
// Reading data from database and printing here, shows zero number of entities always
context.performBlockAndWait({
// Performing batch delete, to remove duplicacy
})
context.performBlockAndWait({
// Creating entities from the JSON read from App bundle
...
...
do {
// Saving local context
try context.save()
context.parentContext?.performBlockAndWait({
do {
try context.parentContext?.save()
// Reading data from database and printing here, shows correct number of entities
} catch {
printDebug("Unable to save main context: \(error)")
}
})
} catch {
printDebug("Unable to save main context: \(error)")
}
})
// Reading data from database and printing here also, shows correct number of entities
I am starting this operation only from once place i.e applicationDidBecomeActive, and also accessing the entity from this operation only.
Any idea, what is the problem ?
So the problem was batch delete using NSBatchDeleteRequest. I was performing same code for multiple type of NSManagedObjectContext, and all are sub-classes of a single NSManagedObjectContext. So that might be the issue.
When I perform fetch-all-and-delete-in-loop, everything works fine, i.e entities are getting stored. But when I use NSBatchDeleteRequest to delete all at once, the entities that are inserted before the batch-delete operation of the next type of NSManagedObjectContext are getting deleted.
So the culprit was NSBatchDeleteRequest. And I don't know why ? I searched but didn't find any solution. So I will post another question regarding this issue.