-
Notifications
You must be signed in to change notification settings - Fork 292
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
Best practice error handling infrastructure moving forward #2181
Labels
best practices
Discussion and details regarding best practices
Comments
davecgh
changed the title
Best practice error handling instracture moving forward
Best practice error handling infrastructure moving forward
May 3, 2020
This was referenced Jul 14, 2020
dnldd
added a commit
to dnldd/dcrd
that referenced
this issue
Oct 25, 2021
This updates the wire error types to leverage go 1.13 errors.Is/As functionality as well as confirm to the error infrastructure best practices outlined in decred#2181.
dnldd
added a commit
to dnldd/dcrd
that referenced
this issue
Oct 25, 2021
This updates the wire error types to leverage go 1.13 errors.Is/As functionality as well as confirm to the error infrastructure best practices outlined in decred#2181.
dnldd
added a commit
to dnldd/dcrd
that referenced
this issue
Nov 1, 2021
This updates the wire error types to leverage go 1.13 errors.Is/As functionality as well as confirm to the error infrastructure best practices outlined in decred#2181.
dnldd
added a commit
to dnldd/dcrd
that referenced
this issue
Nov 4, 2021
This updates the wire error types to leverage go 1.13 errors.Is/As functionality as well as confirm to the error infrastructure best practices outlined in decred#2181.
13 tasks
davecgh
pushed a commit
that referenced
this issue
Dec 5, 2021
This updates the wire error types to leverage go 1.13 errors.Is/As functionality as well as confirm to the error infrastructure best practices outlined in #2181.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I'm opening this issue to document the results of discussions regarding error handling best practices and the direction we would like to move in when adding new error infrastructure and also for updating the existing infrastructure over time. Note that since the changes involve modifications to the public API of the various packages in ways that are not backwards compatible, updates to existing packages will necessarily come with major module version bumps and therefore they should be done when already bumping a module to a new major version for other reasons as well.
Background
A couple of the primary goals of error handling in the dcrd code base is to both provide detailed human-readable errors as well as a way to unambiguously programmatically distinguish the errors without relying on brittle techniques such as looking for specific error strings.
The way that currently is typically achieved is by providing error types that include fields for a detailed description as well as a specific error code of
type ErrorCode int
along with exported constants for the various error codes. This approach allows errors to display detailed human-readable errors while simultaneously allowing callers to programmatically type assert the error to the appropriate upper level type and then access the error code field to compare against the exported error code constants from the package.In code terms, the current approach looks like the following:
Which results in the output:
The current approach has served well and does provide the desired properties, however, it is rather verbose and does not work well with wrapping errors on the way up the stack, which often means errors from lower layers either have to be passed back to the caller unmodified, which loses valuable context, or they have to be converted to the error types of the consumer, which either loses the underlying error code, or forces the consumer to also provide an error code for that underlying condition.
Also, it is often necessary to add additional programmatically detectable errors to existing packages, and since the current approach uses integer error codes in an enum, care must be taken to avoid changing their value to maintain a stable API per semver.
As of Go 1.13, the standard library introduced the
errors.Is
anderrors.As
functions specifically to address aforementioned error issues by allowing errors to be wrapped on their way up the stack while still being easily detectable by a caller.However, using integers to represent error codes in structs that ultimately get wrapped in error stacks is not ideal because the zero value for that error code is indistinguishable from an unset error which requires care to handle properly in many contexts. Instead, it is preferable to provide the programmatically detectable condition via a field of type
error
and provide anUnwrap
method so that it works seamlessly witherrors.Is
anderrors.As
because an unset error is thennil
.Best practice
Putting it all together, the following code demonstrates the new preferred approach as of Go 1.13. Notice that it is not substantially different in character, but it does provide an easier to work with infrastructure that is harder to misuse:
Output:
Notice that it has the following properties:
ErrorKind
typeerrors.New
that can be mutated by callers)errors.As
with automatic unwrappingThe text was updated successfully, but these errors were encountered: