Skip to content

Conversation

@bvaughn
Copy link
Contributor

@bvaughn bvaughn commented Jun 26, 2017

The primary motivation for this diff is to fix an issue with the framesToPop property (added by invariant and others) not being copied over to the "cloned" Error object. This caused problems with Facebook's automated error tooling.

After some discussion with Seb, we decided to just mutate the incoming Error rather than cloning. I also improved the error messaging for string-type errors on the way (as shown below in the screenshots).

screen shot 2017-06-26 at 10 01 03 am

screen shot 2017-06-26 at 10 01 09 am

screen shot 2017-06-26 at 10 01 20 am

Without this property, all fiber errors get lumped together by Facebook's error tooling
Copy link
Collaborator

@sebmarkbage sebmarkbage left a comment

Choose a reason for hiding this comment

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

We should rethink this error cloning strategy. new errorType(errorMessage) is not a valid constructor argument for all types of errors.

Why can't we just mutate the existing error again?


const summary = message ? `${name}: ${message}` : name;

errorMessage = `${summary}\n\nThis error is located at:${componentStack}`;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we just do error.message = errorMessage instead of cloning?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So far as I know (based on very limited testing) that would work.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually I think I was creating a new object to handle the case of a string or null being thrown (instead of an Error) but I can just change the code to only create a new Error in that case.

@bvaughn
Copy link
Contributor Author

bvaughn commented Jun 26, 2017

Why can't we just mutate the existing error again?

I don't recall if we had a specifically reason, other than generally wanting to avoid mutating parameters.


const newError = new errorType(errorMessage);
(newError: any).framesToPop = framesToPop;
newError.stack = errorStack;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is not fully equivalent because debug tooling and such can read the internal slot of this instead of the property name.

errorType = Error;
}

const newError = new errorType(errorMessage);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Like mention above, this constructor may have different signatures than accepting a message for some error types.

@bvaughn bvaughn changed the title Copy 'framesToPop' prop to errors thrown by ReactNativeFiberErrorDialog ReactNativeFiberErrorDialog mutates error message Jun 26, 2017
@bvaughn
Copy link
Contributor Author

bvaughn commented Jun 26, 2017

Pushed the new implementation but it's not showing up. Seems it's because GitHub's webhooks are borked at the moment.

Edit: It's showing up now.

It also better handles string error types.
@bvaughn bvaughn force-pushed the frames-to-pop branch 2 times, most recently from 2612d57 to 93d6ee5 Compare June 26, 2017 18:06
@flarnie
Copy link
Contributor

flarnie commented Jun 26, 2017

"This is an actual error" lol

@bvaughn
Copy link
Contributor Author

bvaughn commented Jun 26, 2017

Yeah, I'm not very creative when running through test cases 😛

@bvaughn
Copy link
Contributor Author

bvaughn commented Jun 26, 2017

Okay I'm going to assume this is good to go. Merging.


// Typically Errors are thrown but eg strings or null can be thrown as well.
if (error && typeof error === 'object') {
if (error instanceof Error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

It might be an error from a different realm but in RN that's unusual or not available at all so this is probably fine. Besides this isn't critical if it gives a false negative.

errorStack = error.stack;
errorType = error.constructor;
errorToHandle = error;
errorToHandle.message = `${summary}\n\nThis error is located at:${componentStack}`;
Copy link
Collaborator

Choose a reason for hiding this comment

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

If this is a frozen object (or non-writable) this will throw. Leaving the error unhandled.

We could use Object.defineProperty(errorToHandle, 'message', { value: ${summary}\n\nThis error is located at:${componentStack} }) but even that might throw for a non-configurable property.

Maybe we should just wrap this in try/catch?

@bvaughn bvaughn merged commit cb32253 into facebook:master Jun 26, 2017
@bvaughn bvaughn deleted the frames-to-pop branch June 26, 2017 19:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants