I have a mobile client that has attempted to update a document that they do not have permission to update (which gets rejected by the sync-gateway). The client now has a different document to everyone else, containing the invalid update. How do I get the clients database to bring back the ‘official’ version of that document?
delete the revision you don’t want.
My problem is that I’m talking to CB lite via the rest API. The http request that updates the document is successful and I get a revision back. How does this client know that the push to the sync-gateway failed? Without knowing that it failed I can’t make the decision to delete the doc.
Whats worse is that subsequent ‘valid’ updates made to the document (by other users who do have permission) seem to be ignored on the device that has the bad document.
So how do I tell in CB Lite (via the rest API) that a document change was forbidden by the sync-gateway in order that I can then deal with it?
The best solution is to make sure you don’t create invalid documents. You can help ensure this by adding a validation function to your database and copying in the same logic that the Sync Gateway’s sync function uses for validating documents.
Couchbase Lite doesn’t have a fine-grained replication error API, so there’s no direct way to tell that a document was rejected by the server. But you can detect the conflict by running an all-docs query after the replication finishes. (In the REST API, use ?only_conflicts=true
in the query and you’ll only get documents that are in conflict.)
Then you can resolve the conflict. FYI, the conflict is the reason the valid update isn’t showing up — the locally-made revision is shadowing it.
Great, I’ll give that a go.
The only_conflicts
flag didn’t return anything. Here’s the url i used:
http://localhost:5984/my-db-name/_all_docs?only_conflicts=true
Is the document I’ve described in conflict though? It was rejected by the sync-gateway because of a forbidden response. Does this cause a document to be in conflict?
Once again, as my posts seem to have vanished…
The problem is that client-side checks for validity are not sufficient (and can never be), because at any point the client could be using stale data. At best client-side checks can only reduce the likelihood of documents being rejected by the server. So its possible that the client thinks it has permission to edit a document but does not, and attempts a document update. The sync-gateway correctly throws a forbidden error and rejects the update. The client now has a doc that is at a different version to everyone else. No more document updates are received for that document.
The _all_docs?only_conflicts=true
query doesn’t seem to show these documents. So my question is again, what is the workaround? I’ve seen the forbidden error being logged in CB Lite, so it must know that the update was rejected… is the information about the rejection stored? Is it accessible?
What platform is this? It may be that the Java or .NET versions of Couchbase Lite haven’t implemented only_conflicts
. (In which case we should fix that.)
It was rejected by the sync-gateway because of a forbidden response. Does this cause a document to be in conflict?
Not directly, no. But once another client successfully updates the document, and the local client pulls it, there will be a conflict. This is what you described earlier when you said future changes don’t appear.
because at any point the client could be using stale data
That mostly doesn’t matter, because the server-side sync function is comparing the revision the client uploads against its parent revision, not against the current revision. It’s fine if the server has a newer revision of the document than the one the client is updating; that just creates a conflict.
If you think the validation failure you got was inevitable due to the distributed nature of the system, could you post details? I think there are scenarios where this could happen, due to user access privileges changing, but they’re probably uncommon.
is the information about the rejection stored? Is it accessible?
No, it’s not stored or notified to the client. That’s something we’ve been meaning to add, but it hasn’t been done yet, partly because (IIRC) no one’s raised it as a serious issue before you.
To reiterate, I’d like to know the details of the situation that happens to you, to get a better idea of the scenarios where this kind of notification is needed. Thanks!
I agree the scenarios when this can could could be considered uncommon, and a well written client can reduce the change of it happening. But its impossible to prevent. For example…
Consider a chat room, where owners can change the name of the chat room. So imagine owner Bob attempts to make a name change, first checking that they are an owner, which they are. Bob submits the name change, while at the same time Jim removes Bob from the list of owners. If Jim’s change makes it to the server first then Bob’s change fails a requireUser() check on the owners and gets rejected. In this case both clients did their job correctly but the error still happens. And now Bob has an inconsistent document, and it will be inconsistent indefinitely, with no indication at all that there is a problem. He has a different view of the world to everyone else.
I guess my issue is that there’s no work around - from what you’re saying Bob has to wait for someone else to make a change at which point the document should be visible in the list of conflicts. And the change may never happen.
I think marking the document in some way, (as being rejected maybe) would be enough that the client could take action to remove the failed version.
That’s a really good point. I’ll do some thinking about what the API might look like. Marking the document is probably not the right thing to do, because the rejection isn’t strictly speaking a property of the document — there can be multiple replications going on, with different servers (think P2P). It’s more like a property of the replication. For example, there’s already (on iOS) a slightly similar property CBLReplication.pendingDocuments
that lists documents that will be pushed by that replication but haven’t been yet. So maybe a property like failedDocuments
that shows which documents failed to upload and why.
Thanks for understanding.
Was there ever a fix added for this?
No, not yet. It would be best to file this as an issue so you can track its status.
All duo, where though?