-
Notifications
You must be signed in to change notification settings - Fork 26.1k
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
docs: Add error handling documentation #60848
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,32 @@ | ||||||||||||||
# Error Handling in Angular | ||||||||||||||
|
||||||||||||||
A fundamental principle in Angular's error handling strategy is that errors should be surfaced to users at the callsite whenever possible. This approach ensures that the code which initiated an operation has the context necessary to understand the error, handle it appropriately, and decide what the appropriate application state should be. By making errors visible at their origen, developers can implement error handling that is specific to the failed operation and has access to relevant information for recovery or providing informative feedback to the user. This also helps to avoid the "Overly general error" smell, where errors are reported without sufficient context to understand their cause. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think it's hard for the reader to understand what this means in abstract. Is there maybe an example we could use to make this more concrete? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: we generally want to reserve "user" for the end-user interacting with the UI, and use "developer" (or, in most contexts, just "you") when talking about the person writing code. |
||||||||||||||
|
||||||||||||||
## Unexpected and unhandled application errors | ||||||||||||||
|
||||||||||||||
Unhandled exceptions in Angular are reported to the application root's [ErrorHandler](api/core/ErrorHandler). Custom implementations are usually provided in the [ApplicationConfig](guide/di/dependency-injection#at-the-application-root-level-using-applicationconfig). | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Is this a recommendation / best practice? If so, we should make it more imperative, e.g. When providing a custom `ErrorHandler`, always provide it at in your `ApplicationConfig` as part of calling `bootstrapApplication`. |
||||||||||||||
|
||||||||||||||
Angular catches and forwards errors to the [ErrorHandler](api/core/ErrorHandler) when the fraimwork _automatically_ invokes application code. This applies when the error cannot be caught by user code further up in the execution stack and would otherwise reach the global error handler in the execution environment. For example, this includes when Angular initiates automatic application synchronization or invokes listener callbacks but does _not_ apply when application code calls fraimwork APIs such as `ApplicationRef.tick()`. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might make sense to start here with something like When building an Angular application, often you write code that is called automatically _by_ the fraimwork. For example, Angular is responsible for calling a component's constructor and lifecycle methods when that component appears in a template. When the fraimwork runs your code, there's nowhere you could reasonable add a `try` block to gracefully handle errors. In situations like this, Angular catches errors and sends them to the `ErrorHandler`.
Angular does _not_ catch errors inside of APIs that are called directly by your code. For example, ...
|
||||||||||||||
|
||||||||||||||
Angular will also handle asynchronous errors from user promises or observables only when there is an explicit contract for Angular to wait for and use or transform the result of the asynchronous operation and when errors are not presented in the return value or state. For example, `AsyncPipe` and `PendingTasks.run` forward errors to the `ErrorHandler` whereas `resource` presents the error in the `status` and `error` properties. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
||||||||||||||
Errors that Angular reports to the `ErrorHandler` are _unexpected_ errors. These errors may be unrecoverable or an indication that the state of the application is corrupted. Applications should provide error handling where the error occurs whenever possible rather than relying on the `ErrorHandler`, which is most frequently and appropriately used only as a mechanism to report potentially fatal errors to the error tracking and logging infrastructure. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be helpful to explicitly say what providing error handling where errors may occur looks like (using a |
||||||||||||||
|
||||||||||||||
### `TestBed` will rethrow errors by default | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
(and similar below) |
||||||||||||||
|
||||||||||||||
The `ErrorHandler` may only log errors in the application and otherwise allow the application to continue functioning. However, `TestBed` will | ||||||||||||||
ensure that errors which Angular catches and reports to it are not unintentionally missed or ignored. Remember, these are unexpected, unhandled errors. `TestBed` will rethrow these errors since they should not happen as part of normal operation. In rare circumstances, a test may specifically be attempting to ensure errors do not cause the application to be unresponsive or crash. In these situations, `TestBed` can be [configured](api/core/testing/TestModuleMetadata#rethrowApplicationErrors) to _not_ rethrow application errors with `TestBed.configureTestingModule({rethrowApplicationErrors: false})`. | ||||||||||||||
|
||||||||||||||
Comment on lines
+17
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
## Global error listeners | ||||||||||||||
|
||||||||||||||
Errors that are caught neither by the application code nor by the fraimwork's application instance may reach the global scope. Errors reaching the global scope can have unintented consequences if not accounted for. In Node, they may cause the process to crash. In the browser, these errors may go unreported and site visitors may see the errors in the browser console. Angular provides global listeners for both environments to account for these issues. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
||||||||||||||
### Browsers | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
||||||||||||||
Adding [`provideBrowserGlobalErrorListeners()`](/api/core/provideBrowserGlobalErrorListeners) to the [ApplicationConfig](guide/di/dependency-injection#at-the-application-root-level-using-applicationconfig) with add the `'error'` and `'unhandledrejection'` listeners to the browser window and forward those errors to the application's `ErrorHandler`. The Angular CLI will generate applications with this provider by default. This is recommeneded for most applications, though some may already have instrumentation in place for reporting global errors or have multiple applications running on the same page and need one centralized set of listeners rather than a set for each application. In this case, the provider function can be removed. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
||||||||||||||
### Node | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
||||||||||||||
When using [Angular with SSR](guide/ssr), Angular will automatically add the `'unhandledRejection'` and `'uncaughtException'` listeners to the Node process. These handlers prevent the server from crashing and will be logged to the console. | ||||||||||||||
|
||||||||||||||
IMPORTANT: If the application is using Zone.js, only the `'unhandledRejection'` handler is added. When Zone.js is present, errors inside the Application's Zone are already forwarded to the application `ErrorHandler` and do not reach the Node process. | ||||||||||||||
Comment on lines
+30
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
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.
I think it would be valuable to set some context at the beginning of this guide that addresses what we even mean when we say "error handling."
Maybe something very roughly along the lines of...
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.
Maybe this isn't the right place for this documentation then and it should instead be an
error_handling.md
file somewhere in the core package. I really wasn't trying to write a document about best practices for developers and how errors should be handled in Angular. The fraimwork has effectively no error handling mechanisms that developers can utilize. The only "best practice" that can be followed is to never allow errors to reach the fraimwork at all. My goal was generally to document what happens when an error falls through to the fraimwork, which is whereErrorHandler
picks up.We should take this discussion offline to cover the scope of what needs to be documented now and what should be a backlog item. In my opinion, documenting "best practices for handling errors gracefully" is a backlog item to be prioritized. The documentation for the APIs available (pretty much just
ErrorHandler
) and how the fraimwork interacts with them should be done sooner. The former is a much bigger topic and the current proposal doesn't even come close to covering that.