Skip to content

Conversation

@dawidreedsy
Copy link
Contributor

After doing the steps:

  1. Create a doc with rich text type (or any other non irreversible type)
  2. Make op submission fail
  3. Now in the hard rollback we do this._setType(null);
  4. If there is any op comming before the hard rollback fetch is finished, we get the error
Cannot submit op. Document has not been created.

as in the _submit we do:

    if (!this.type) {
      var err = new ShareDBError(
        ERROR_CODE.ERR_DOC_DOES_NOT_EXIST,
        'Cannot submit op. Document has not been created. ' + this.collection + '.' + this.id
      );
      if (callback) return callback(err);
      return this.emit('error', err);
    }

We definitely do not handle this case properly. Possible solutions:

  1. Just throw error whenever that happens, which is easy to implement and it is not really breaking. User would be then able to react on the error or just ignore it.
  2. Store copy of cannonical snapshot in the doc itself, so that we do not have to do fetch for hard rollback. More difficult to implement and has a side effect of storing the doc twice in the memory.

@dawidreedsy dawidreedsy force-pushed the bug-fix/broken-hard-rollback branch 3 times, most recently from 70e8163 to d6842e4 Compare March 3, 2025 16:28
@coveralls
Copy link

coveralls commented Mar 3, 2025

Coverage Status

coverage: 97.491% (+0.004%) from 97.487%
when pulling fd67b16 on bug-fix/broken-hard-rollback
into ca50594 on master.

Copy link
Collaborator

@alecgibson alecgibson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test, please!

Comment on lines +753 to +757
if (this._isInHardRollback) {
var err = new ShareDBError(
ERROR_CODE.ERR_DOC_IN_HARD_ROLLBACK,
'Cannot submit op. Document is performing hard rollback. ' + this.collection + '.' + this.id
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could just move this after the var err = new ShareDBError(ERR_DOC_DOES_NOT_EXIST) to override this "default" error and then avoid having to duplicate the emit() machinery

@dawidreedsy
Copy link
Contributor Author

dawidreedsy commented Mar 4, 2025

Yes i know want to prepare the test today, just need to fiddle a bit to make it work. Just wanted to push it first, so the @ericyhwang get a chance to look into it before the meeting :)

@dawidreedsy dawidreedsy force-pushed the bug-fix/broken-hard-rollback branch 3 times, most recently from a8e8f0c to 814e814 Compare March 4, 2025 15:53
After doing the steps:
1. Create a doc with rich text type (or any other non irreversible type)
2. Make op submission fail
3. Now in the hard rollback we do `this._setType(null);`
4. If there is any op comming before the hard rollback `fetch` is finished, we get the error
```
Cannot submit op. Document has not been created.
```
as in the `_submit` we do:
```typescript
    if (!this.type) {
      var err = new ShareDBError(
        ERROR_CODE.ERR_DOC_DOES_NOT_EXIST,
        'Cannot submit op. Document has not been created. ' + this.collection + '.' + this.id
      );
      if (callback) return callback(err);
      return this.emit('error', err);
    }
```

We definitely do not handle this case properly. Possible solutions:
1. Just throw error whenever that happens, which is easy to implement
   and it is not really breaking. User would be then able to react on
   the error or just ignore it.
2. Store copy of cannonical snapshot in the doc itself, so that we do
   not have to do fetch for hard rollback. More difficult to implement
   and has a side effect of storing the doc twice in the memory.
@dawidreedsy dawidreedsy force-pushed the bug-fix/broken-hard-rollback branch from 814e814 to 6f3869c Compare March 4, 2025 15:57
@dawidreedsy
Copy link
Contributor Author

To be honest i think there might be more to this than just my fix as before fetch we do

  this._setType(null);
  this.version = null;
  this.inflightOp = null;
  this.pendingOps = [];

and after fetch is finished

    if (inflightOp) pendingOps.unshift(inflightOp);
    var allOpsHadCallbacks = !!pendingOps.length;
    for (var i = 0; i < pendingOps.length; i++) {
      allOpsHadCallbacks = util.callEach(pendingOps[i].callbacks, err) && allOpsHadCallbacks;
    }
    if (err && !allOpsHadCallbacks) doc.emit('error', err);
    doc._isInHardRollback = false;
```,

I think it was menat to reject all ops that were added after fetch started. I am not sure just throwing the above error wouldn't break anything. Even though all tests are passing.


if (!pendingOps.length) return;
if (!pendingOps.length) {
doc._isInHardRollback = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to avoid potential future issues with forgetting to reset _isInHardRollback on early returns, we could reset to false at the top of this _fetch callback

@dawidreedsy dawidreedsy force-pushed the bug-fix/broken-hard-rollback branch from 0857be5 to fd67b16 Compare March 4, 2025 17:26
@dawidreedsy dawidreedsy merged commit 2b38f47 into master Mar 4, 2025
7 checks passed
@dawidreedsy dawidreedsy deleted the bug-fix/broken-hard-rollback branch March 4, 2025 17:28
dawidreedsy added a commit that referenced this pull request Mar 6, 2025
 Similar case to:
 - #692

 however instead of submitting ops to doc is when we submit doc presence
dawidreedsy added a commit that referenced this pull request Mar 6, 2025
 Similar case to:
 - #692

 however instead of submitting ops to doc is when we submit doc presence
@dawidreedsy dawidreedsy changed the title 🐛 Unhandled rejection when submitting ops during hard rollback. 🐛 Wrong error when submitting ops during hard rollback. Mar 6, 2025
dawidreedsy added a commit that referenced this pull request Mar 11, 2025
…#693)

Similar case to:
 - #692

 however instead of submitting ops to doc is when we submit doc presence
longlonggoo added a commit to longlonggoo/longlonggoo that referenced this pull request Aug 13, 2025
… (#693)

Similar case to:
 - share/sharedb#692

 however instead of submitting ops to doc is when we submit doc presence
FernhillFable added a commit to FernhillFable/cluster that referenced this pull request Aug 13, 2025
… (#693)

Similar case to:
 - share/sharedb#692

 however instead of submitting ops to doc is when we submit doc presence
adelinedaosen added a commit to adelinedaosen/ServiceNow that referenced this pull request Sep 12, 2025
… (#693)

Similar case to:
 - share/sharedb#692

 however instead of submitting ops to doc is when we submit doc presence
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants