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

"An object could not be cloned" when promise is rejected with an error #44

Open
cdhowie opened this issue Jan 12, 2017 · 3 comments
Open

Comments

@cdhowie
Copy link

cdhowie commented Jan 12, 2017

It's considered a best practice to only reject promises with an Error (or derived object). Unfortunately, this breaks operative as errors can't be cloned. This results in an uncaught error within operative's returnResult in the context of the web worker, leaving the primary thread hanging waiting for a response that will never arrive.

I believe that operative should handle this case somehow. If the error can't be cloned via postMessage then we need to do something to tell the main thread that the operation failed -- either transfer the error object using JSON (which can serialize errors, albeit without their functions/prototype) or some other kind of operative-specific error that wraps a structured-cloning-compatible version of the rejection error.

As it stands right now, operative's promise interop is all but useless since it is completely unable to proxy rejections back to the main thread.

padolsey added a commit that referenced this issue Jan 15, 2017
 - See #44
 - Specifically pass message/stack and then catch on the other side
@padolsey
Copy link
Owner

Thanks for reporting this. I'm not sure which is the best route to take here. Please see #45 and let me know if this fixes your case / and if you think that's a generally fair approach.

@cdhowie
Copy link
Author

cdhowie commented Jan 15, 2017

I think that approach probably makes some sense. I'm wondering if it would be beneficial to also transfer the name and code attributes. name is standard, and while it is supposed to indicate the class of the error (something we can't really do since we don't want to try finding the right prototype on the other side -- and indeed the prototype might not even be available outside of the worker) I would argue that it's better to have that than not to have it.

code is used in a lot of places in Node to convey the exact condition of the error (in the AWS SDK it is used very heavily) and a lot of npm modules make use of this convention. When they are used in a web application via bundling, it would be nice if this attribute could be proxied over as well.

Of course, we could wind up down a rabbit trail where we are building an ever-increasing list of things that we need to transfer.

An alternative approach would be to simply pass back a JSON-encoded version of the error object. This will catch any attributes/structures that can be represented in JSON, which should be pretty much anything of value. (Usually we don't try to intentionally pass functions on Error objects.)

@padolsey
Copy link
Owner

Just released 0.4.6 which manually clones over any props on native Error objs. Hope that solves your use-case. See specs here:

describe('Rejecting with an error', function() {
it('Should reject correctly', function(done) {
var op = operative(function() {
var deferred = this.deferred();
deferred.reject(new Error('foo 789'));
});
op().then(function() {
expect(true).to.be.false; // fail
done();
}).catch(function(err) {
expect(err.message).to.equal('foo 789'); // pass
done();
});
});
describe('With additional props', function() {
it('Should reject correctly and be received with props', function(done) {
var op = operative(function() {
var deferred = this.deferred();
var error = new Error('foo');
error.custom = 123;
deferred.reject(error);
});
op().then(function() {
expect(true).to.be.false; // fail
done();
}).catch(function(err) {
expect(err.message).to.equal('foo');
expect(err.custom).to.equal(123);
done();
});
});
});
});

(Thanks for reporting this, once again!)

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

No branches or pull requests

2 participants