-
Notifications
You must be signed in to change notification settings - Fork 47.2k
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
Use a Wrapper Error for onRecoverableError with a "cause" Field for the real Error #28736
Conversation
We log it as recoverable in a side-channel.
This way they're associated with the error that was thrown. This means that if there's more than one, there's multiple appendix for each one. However, since we're now unwinding early this doesn't actually happen in practice.
This makes it a little easier to group and display as a single error in UIs. The error is that it caused client rendering - the cause is the other error. We also exclude the appendix when it's a hydration mismatch since that has its own description of what happened and no other cause.
be80438
to
bcc746d
Compare
Comparing: 7a2609e...60a2424 Critical size changesIncludes critical production bundles, as well as any change greater than 2%:
Significant size changesIncludes any change greater than 0.2%: Expand to show
|
renderDidError(value); | ||
const wrapperError = new Error( | ||
'There was an error during concurrent rendering but React was able to recover by ' + | ||
'instead synchronously rendering the entire root.', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically I think we could error in the sync pass and then recover in the second sync pass. We could check if this is actually a concurrent render first but we don't really expect this case.
Follow up to #28684. V8 includes the message in the stack and printed errors include just the stack property which is assumed to contain the message. Without this, the prefix doesn't get printed in the console. <img width="578" alt="Screenshot 2024-04-03 at 6 32 04 PM" src="https://github.com/facebook/react/assets/63648/d98a2db4-6ebc-4805-b669-59f449dfd21f"> A possible alternative would be to use a nested error with a `cause` like #28736 but that would need some more involved serializing since this prefix is coming from the server. Perhaps as a separate attribute.
Follow up to #28684. V8 includes the message in the stack and printed errors include just the stack property which is assumed to contain the message. Without this, the prefix doesn't get printed in the console. <img width="578" alt="Screenshot 2024-04-03 at 6 32 04 PM" src="https://github.com/facebook/react/assets/63648/d98a2db4-6ebc-4805-b669-59f449dfd21f"> A possible alternative would be to use a nested error with a `cause` like #28736 but that would need some more involved serializing since this prefix is coming from the server. Perhaps as a separate attribute. DiffTrain build for [583eb67](583eb67)
…he real Error (#28736) We basically have four kinds of recoverable errors: - Hydration mismatches. - Server errored but client didn't. - Hydration render errored but client render didn't (in Root or Suspense boundary). - Concurrent render errored but synchronous render didn't. For the first three we log an additional error that the root or Suspense boundary didn't error. This provides some context about what happened. However, the problem is that for hydration mismatches that's unnecessary extra context that is confusing. We also don't log any additional context for concurrent render errors that could recover. This used to be the only recoverable error so it didn't need extra context but now we need to distinguish them. When we log these to `reportError` it's confusing to just see the error because you didn't see anything error on the page. It's also hard to group them together as one. In this PR, I remove the unnecessary context for hydration mismatches. For hydration and concurrent errors, I now wrap them in an error that describes that what happened but then use the new `cause` field to link the original error so we can keep that as the cause. The error that happened was that hydration client rendered or you deopted to sync render, the cause of that error is some other error. For server errors, we control the Error object so I already had added some context to that error object's message. Since we hide the message in prod, it's nice not to have the raw message in DEV neither. We could potentially split these into two errors for parity though. DiffTrain build for [6090cab](6090cab)
Follow up to facebook#28684. V8 includes the message in the stack and printed errors include just the stack property which is assumed to contain the message. Without this, the prefix doesn't get printed in the console. <img width="578" alt="Screenshot 2024-04-03 at 6 32 04 PM" src="https://github.com/facebook/react/assets/63648/d98a2db4-6ebc-4805-b669-59f449dfd21f"> A possible alternative would be to use a nested error with a `cause` like facebook#28736 but that would need some more involved serializing since this prefix is coming from the server. Perhaps as a separate attribute.
…he real Error (facebook#28736) We basically have four kinds of recoverable errors: - Hydration mismatches. - Server errored but client didn't. - Hydration render errored but client render didn't (in Root or Suspense boundary). - Concurrent render errored but synchronous render didn't. For the first three we log an additional error that the root or Suspense boundary didn't error. This provides some context about what happened. However, the problem is that for hydration mismatches that's unnecessary extra context that is confusing. We also don't log any additional context for concurrent render errors that could recover. This used to be the only recoverable error so it didn't need extra context but now we need to distinguish them. When we log these to `reportError` it's confusing to just see the error because you didn't see anything error on the page. It's also hard to group them together as one. In this PR, I remove the unnecessary context for hydration mismatches. For hydration and concurrent errors, I now wrap them in an error that describes that what happened but then use the new `cause` field to link the original error so we can keep that as the cause. The error that happened was that hydration client rendered or you deopted to sync render, the cause of that error is some other error. For server errors, we control the Error object so I already had added some context to that error object's message. Since we hide the message in prod, it's nice not to have the raw message in DEV neither. We could potentially split these into two errors for parity though.
…he real Error (#28736) We basically have four kinds of recoverable errors: - Hydration mismatches. - Server errored but client didn't. - Hydration render errored but client render didn't (in Root or Suspense boundary). - Concurrent render errored but synchronous render didn't. For the first three we log an additional error that the root or Suspense boundary didn't error. This provides some context about what happened. However, the problem is that for hydration mismatches that's unnecessary extra context that is confusing. We also don't log any additional context for concurrent render errors that could recover. This used to be the only recoverable error so it didn't need extra context but now we need to distinguish them. When we log these to `reportError` it's confusing to just see the error because you didn't see anything error on the page. It's also hard to group them together as one. In this PR, I remove the unnecessary context for hydration mismatches. For hydration and concurrent errors, I now wrap them in an error that describes that what happened but then use the new `cause` field to link the original error so we can keep that as the cause. The error that happened was that hydration client rendered or you deopted to sync render, the cause of that error is some other error. For server errors, we control the Error object so I already had added some context to that error object's message. Since we hide the message in prod, it's nice not to have the raw message in DEV neither. We could potentially split these into two errors for parity though. DiffTrain build for commit 6090cab.
We basically have four kinds of recoverable errors:
For the first three we log an additional error that the root or Suspense boundary didn't error. This provides some context about what happened. However, the problem is that for hydration mismatches that's unnecessary extra context that is confusing. We also don't log any additional context for concurrent render errors that could recover. This used to be the only recoverable error so it didn't need extra context but now we need to distinguish them. When we log these to
reportError
it's confusing to just see the error because you didn't see anything error on the page. It's also hard to group them together as one.In this PR, I remove the unnecessary context for hydration mismatches.
For hydration and concurrent errors, I now wrap them in an error that describes that what happened but then use the new
cause
field to link the original error so we can keep that as the cause. The error that happened was that hydration client rendered or you deopted to sync render, the cause of that error is some other error.For server errors, we control the Error object so I already had added some context to that error object's message. Since we hide the message in prod, it's nice not to have the raw message in DEV neither. We could potentially split these into two errors for parity though.