Open silverwind opened 5 years ago
For now we'd rather not allow it because it makes it too easy to swallow errors (such as if the error boundary itself is buggy).
Right, I see reasoning in that, preventing error logging should require more than just the existance of a boundary.
Browsers allow to suppress logging uncaught errors to the console via event.preventDefault()
in a error
event handler on window
. Maybe a something similar could be done from a error boundary too, like error.preventDefault()
.
Error swallowing should be opt-in. I'd like to swallow certain errors and not others:
componentDidCatch(error) {
// I'd like to swallow the error
if (error instanceof MyExpectedError) {
// somehow suppress the error?
}
}
I'd support this feature as it would be nice to de-clutter our test output.
@gaearon
consider the following production issue we are facing:
We are using a third party logging service, that logs all console.error
calls automagically- which is debatably awesome and at the same time a given fact.
Naturally, we have our own ErrorBoundary implementation: We want to slap on extra information special to the boundary instance- So our error boundary component receives this information as props / context, And logs the error along this information using the third party's sdk when an error occurs.
As a result of this implementation, when a component fails, we have two separate errors logged in our monitoring pipeline:
One which react logs, with barely any info, which comes from console.error
And one with everything we need to know, which we explicitly logged via the third party library.
Since this redundancy is confusing and not acceptable We are now facing quite a dilemma:
If we don't explicitly log, we lose error specific info. We also rely on react to do the logging for us, which is a bad idea in the long run.
if we explicitly log - we get two separate events in our monitoring pipeline, which is confusing and noisy, since our monitoring pipeline is automated and triggers a whole lot of internal processes.
I bet that we both believe console.error
to be a side effect.
As an app developer, wouldn't you agree with me that such a side effect should not be invoked by a UI library without the possibility to opt out?
It's great that I can isolate failures to granular regions in the application- anything other than that, should not be decided for me as a developer. I wouldn't want to see anything in the console which I did not put there. Especially if it renders the entire stack of my component tree structure, uglified or not.
On the other hand, I do understand where you're coming from by saying you don't want it to be easy to swallow errors, so how about this as middle ground:
You could move the invocation of console.error
to componentDidCatch
,
Which would be the default implementation unless overriden.
if you think of it, this is the correct thing to do, since componentDidCatch
is meant for exactly this.
To quote the docs:
componentDidCatch() is called during the “commit” phase, so side-effects are permitted. It should be used for things like logging errors
you say console.error
and I say thirdPartyLibrary.logError
.
The means of logging should be up to app developers, especially if they went through the trouble of setting up Error Boundaries.
Since Error Boundaries are basically logging components with some conditional rendering, and since I bet our logging provider is not the only one which logs console.error
calls, wouldn't you say this issue should be solved in a more extensible manner?
As for buggy error boundaries, IMHO, you should not care about them. It's just another failed component, so let it fail until it either crashes the entire tree or another boundary catches it. Since react is solely a UI rendering library, why should it decide what happens when rendering fails?
@EyalPerry hit the nail on the head. Is there anything more to say? Shall we patch console.error
?
@anilanar I completely agree with you, I think we should really have the possibility to suppress the logging of some errors which have been handled in error boundaries.
I think that we should have the power and responsibility to decide what to log and what not to log, especially in production.
In my case, if my app has been deployed in production and an error boundary catches an error, I wouldn't want to log the error to the console leading to information disclosure for some "more smart" users who open the browser's console to see what went wrong, or at least, I would want to be able to decide whether to log a certain error captured by an error boundary or not.
Also, I think that, when using create-react-app
, it would be great to have the ability to suppress the error overlay for some errors caught by the error boundary (not all, but some), but that's another story...
It would be nice to have a control on logging errors to console.
For example, I like to use Error Boundaries for handling 404 exceptions in my apps. This way I don't need to call a redirect to some route or put the rendering logic inside my components.
Regularly I just throw a NotFoundException
and seeing an error in console is not something I expect.
I would agree with @EyalPerry that moving the logging into default componentDidCatch would be a nice solution.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution.
Don’t close. We can’t seriously unconditionally log this anymore.
I have the opposite problem. Error is not logged to console in dev build.
The above error occurred in the...
, but nothing is above.
So if I console.error
it in componentDidCatch
it works in dev, but now I have two duplicate errors logged in prod.
v16.13.1
I'd like this to be fixed as well. The solution @EyalPerry suggested would be perfect.
I vote for this too. I am also using an error handling mechanism like the one described by @ElForastero.
Does anyone have a workaround for this while testing? I want to real-render a component under test, catch the error, and make an assertion without seeing error logging, especially as one can't hide logging in jest.
Does anyone have a workaround for this while testing? I want to real-render a component under test, catch the error, and make an assertion without seeing error logging, especially as one can't hide logging in jest.
This is my hacky workaround:
const swallowErrors = yourTestFn => {
const error = console.error
console.error = () => {}
yourTestFn()
console.error = error
}
// Then your test
it('tests something without console log' , () => {
swallowErrors(()=>{
const wrap = mount(<ErBoundary><Child/></ErBoundary>)
// ... expect errors ...
})
})
Or, you can do as this guy here
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
Bump.
Bump.
bump. so many logs i want gone
Bump
This is resulting in double errors in our logging system (ErrorBoundary logs it but we also capture console.error) – extremely frustrating.
The errors are also unconditionally logged during tests where I expect components to throw and catch the errors myself with error boundaries. This is frustrating and pollutes test output.
I suppose this is still not fixed in React 18 alpha. We still have hopes for stable 18 release.
@gaearon is there any way to prioritize this or would you accept PRs to fix it?
We are running into a similar problem as @EyalPerry mentioned. It would be great to fix this
@gaearon Would also like to see this fixed. I think ErrorBoundary should have same semantics as exception handling, once an exception has been caught, it's caught.
If you want to log your exceptions, you should log them in the catch()
, having a helper that logs the error exactly like it's currently logged might be useful. I guess this would be a breaking change, but IMO it's worth to have the same semantics as normal exception handling. If breaking change is too big of a problem, then having a .preventDefault()
/.preventLogging()
works too.
If the exception handler (ErrorBoundary) itself causes an exception, that's a different case, and should cause an exception to bubble up (which presumably could be caught by a higher level handler/ErrorBoundary).
For me there's two main reasons: 1) Nicer DX/UX, we know that in some cases some components will fail, and thus use fallback components, spamming the console isn't very nice. The console messages would lead people to think that something is broken, even though it has already been handled gracefully, by the fallback component. 2) E2e tests, we use playwright, and it would be nice to have all tests confirm at the end of the test that there were no log entries. It's too easy for developers to not notice something in the log, and having e2e tests that double check is useful.
My team ran into this issue as well. Would really like a fix.
Yeah, being able to control this logging behavior would be awesome. We are using an extensive logging system and it would be nice to be able to combine the error and the component stack into a single log message this way. While just hiding the second component stack error message is not difficult, detecting the previous "uncaught" window error is the major issue as there's no ways to identify that it originated from within react.
I'm exploring a pattern in which I throw specific errors when running into unexpected scenarios (i.e. missing or invalid parameters, invalid routes, ...) with the intention of moving all of this UI state logic to error boundaries instead rather than repeating it in every page/view. It makes things a lot cleaner, but the unfortunate side-effect is indeed that all of these errors now show up as uncaught errors in the console. Would really love a way to be able to bail out of logging expected errors.
I do understand that intentionally throwing errors does not mean that they are also caught, if you for example forget to handle them in an error boundary, or simply forget to wrap your tree with an error boundary component. Not really sure what the best way around this would be.
Error stacks are ludicrous when testing error boundaries 😬 yikes.
bump
bump
The duplicate logging (once from console, once from error boundary), is troublesome for user's who've configured Sentry error monitoring that way.
Considering there exists API to do this for hydration errors with onRecoverableError
https://github.com/facebook/react/pull/23207, is there more appetite for exposing this more publically?
I wouldn't even mind if it's a method I can monkeypatch with a Proxy, if labelled appropriately consumers can take the necessary risks. I did something similar with Next.js (https://github.com/vercel/next.js/discussions/36641) to log out hydration errors since Next.js framework doesn't expose this themselves.
This is a huge pain and makes the console unreadable in dev mode as well as distracting/scary in prod mode. Some of our errors are "normal" / "handled" for some users or configurations. For instance, if a component doesn't have the rights to do something, an ErrorBoundary will catch that and show a nice UI. We also use Suspense and the two tie well together.
What I ended up doing to workaround this limitation:
1) Tag (e.g, InvariantError extends Error
) my custom Errors
2) override console.error with my own to ignore any instance of the above custom error. This is for production builds.
3) Likewise, add an error
listener on window and event.preventDefault()
if event.error
is an instance of my custom error. This is for dev builds. This is thanks to this amazing code: https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberErrorLogger.js#L93
It really shouldn't be this complicated and undocumented.
bump
I'm running into this as well for reasons similar to those explained by @AlexGalays. This is a rather unintuitive limitation.
bump
Also spent several hours trying to figure out why there are still errors in the console after I had added an error boundary. But it looks like React 19 adds options for handling errors 🤞
yes it's a good change - I think you can consider this issue closed, you can use the new options to override the default behaviour to ping console.error
in React 19. Here's the setup I use in my test app:
import { createRoot } from "react-dom/client";
const container = document.getElementById(“app”);
const root = createRoot(container, {
// Callback called when an error is thrown and not caught by an ErrorBoundary.
onUncaughtError: (error, errorInfo) => {
// only log in dev environments
if (IS_DEV) {
console.warn('Uncaught error', error, errorInfo.componentStack);
}
}),
// Callback called when React catches an error in an ErrorBoundary.
onCaughtError: (error, errorInfo) => {
// do not log errors handled by error boundaries
}),
// Callback called when React automatically recovers from errors (for ex. hydration errors)
onRecoverableError: (error, errorInfo) => {
console.warn('Recoverable error', error, errorInfo.componentStack);
}),
});
root.render();
Thanks @AbhiPrasad .
The default should be changed however. Caught errors shouldn't be logged to the console by default. That's how things work in general everywhere, e.g. in try-catch statements.
Now all the app and test developers have to change their implementation of mounting React to avoid unnecessary console logs.
I noticed this unconditional
console.error
which I'd like to prevent to keep the console clean from errors that are already "caught" in an error boundary.Maybe a condition on
capturedError.errorBoundaryFound
could prevent this logging?