Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Errors swallowed in stopped subscribers #3461

Closed
cartant opened this issue Mar 22, 2018 · 8 comments
Closed

Errors swallowed in stopped subscribers #3461

cartant opened this issue Mar 22, 2018 · 8 comments
Assignees
Labels
AGENDA ITEM Flagged for discussion at core team meetings

Comments

@cartant
Copy link
Collaborator

cartant commented Mar 22, 2018

RxJS version: 6.0.0-beta.1

Code to reproduce: See #3444

Expected behavior:

Errors should not be swallowed.

Actual behavior:

Errors are swallowed.

Additional information:

The Subscriber.prototype.error implementation:

error(err?: any): void {
  if (!this.isStopped) {
    this.isStopped = true;
    this._error(err);
  }
}

swallows any errors that are passed to a stopped subscriber.

See #3444 for a repro. The internal error is swallowed because the subscriber to which it is passed is stopped at the time the error occurs.

@cartant cartant changed the title Errors swallowed in stopped subscibers Errors swallowed in stopped subscribers Mar 22, 2018
@benlesh
Copy link
Member

benlesh commented Mar 22, 2018

This is by design. If a Subscriber has already been notified of completion or error, we do not want it to be notified again in a reentrant way.

@cartant
Copy link
Collaborator Author

cartant commented Mar 22, 2018

But should the error be completely ignored - i.e. not re-thrown or otherwise ensured to be unhandled? At the moment, the implementation of Subscriber.prototype.error hides the implementation error in #3444 - calling next on a null property.

cartant added a commit to cartant/rxjs that referenced this issue Mar 24, 2018
It's sometimes possible for operator implementations to effect calls to
`error` after `unsubscribe` has been called - i.e. when the subscriber
is stopped. See ReactiveX#3444. Prior to this commit, such errors were swallowed.

Closes ReactiveX#3461
@cartant
Copy link
Collaborator Author

cartant commented Mar 24, 2018

The problem is in the implementation of _trySubscribe:

protected _trySubscribe(sink: Subscriber<T>): TeardownLogic {
  try {
    return this._subscribe(sink);
  } catch (err) {
    if (config.useDeprecatedSynchronousErrorHandling) {
      sink.syncErrorThrown = true;
      sink.syncErrorValue = err;
    }
    sink.error(err);
  }
}

If there is a subscriber in the list of sinks - the subscribers chained together using the destination property - that happens to be closed/stopped, the error will be swallowed.

The only way that I can see that this could be fixed would be to walk the chain of subscribers and if a closed/stopped subscriber is found, rethrow the error or call hostReportError depending upon the useDeprecatedSynchronousErrorHandling configuration setting.

cartant added a commit to cartant/rxjs that referenced this issue Mar 24, 2018
If _trySubscribe catches an error and the sink - or one of its
destinations - is stopped and the sink's error method is called, the
error is swallowed - as it cannot be reported via the observer's
callback. This commit adds an internal reportError method to Subscriber.
The method defers to the appropriate error reporting mechanism if a
stopped subscriber is found.

Closes ReactiveX#3461
cartant added a commit to cartant/rxjs that referenced this issue Mar 24, 2018
If _trySubscribe catches an error and the sink - or one of its
destinations - is stopped and the sink's error method is called, the
error is swallowed - as it cannot be reported via the observer's
callback. This commit adds an internal reportError method to Subscriber.
The method defers to the appropriate error reporting mechanism if a
stopped subscriber is found.

Closes ReactiveX#3461
cartant added a commit to cartant/rxjs that referenced this issue Mar 27, 2018
If _trySubscribe catches an error and the sink - or one of its
destinations - is stopped and the sink's error method is called, the
error is swallowed - as it cannot be reported via the observer's
callback. This commit adds an internal reportError method to Subscriber.
The method defers to the appropriate error reporting mechanism if a
stopped subscriber is found.

Closes ReactiveX#3461
@benlesh
Copy link
Member

benlesh commented Apr 2, 2018

So to clarifiy, you're saying that in this case:

new Observable(subscriber => {
  subscriber.error(new Error('first one'));
  subscriber.error(new Error('second one'));
})
.subscribe({
  error(err) { console.log(`handled ${err.message}`); }
});

We should see the first one log as handled, and the second one should be rethrown (in another callstack)?

@benlesh benlesh added the AGENDA ITEM Flagged for discussion at core team meetings label Apr 2, 2018
@cartant
Copy link
Collaborator Author

cartant commented Apr 2, 2018

I've just realised that I've replied to the above comment - which I read in an email - here, in the related PR conversation.

@cartant
Copy link
Collaborator Author

cartant commented May 23, 2018

This issue probably should be closed.

I'll create a new issue that better describes the repro and motivation - if I can't recall it myself, this issue is unhelpful - and will include a snippet similar the one in this comment that instead reports errors to the console if they cannot be reported to the observer.

@cartant
Copy link
Collaborator Author

cartant commented Jun 6, 2018

Closing this in favour of #3803 - which is, hopefully, a more clear description of the problem.

@cartant cartant closed this as completed Jun 6, 2018
@cartant
Copy link
Collaborator Author

cartant commented Jun 6, 2018

@benlesh I've closed this in favour of #3803. This issue still has the "Agenda Item" and "Discussion" labels. My recollection from the last meeting was that consensus was reached regarding the reporting of errors to the console. If that's not the case, you might want to apply the labels to #3803.

@lock lock bot locked as resolved and limited conversation to collaborators Jan 18, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
AGENDA ITEM Flagged for discussion at core team meetings
Projects
None yet
Development

No branches or pull requests

2 participants