Is error type in Go "Error" or "error"? It bugged me that in the Tour it is with small first letter so I looked around and found here with small e yet here in source code it is with big capital letter.
Also how can it be without big capital letter yet still visible outside of package?
Just started learning Go so I might have missed something basic, thanks.
error is the type, lowercase. Just like with int and string it doesn't need to be visible as it is built-in to Go:
A good blog post on error handling
The runtime package you're referring to has an Error interface. The type there is an interface not error:
Package runtime
type Error interface {
error
// RuntimeError is a no-op function but
// serves to distinguish types that are run time
// errors from ordinary errors: a type is a
// run time error if it has a RuntimeError method.
RuntimeError()
}
The Error interface identifies a run time error.
Related
When working with go there is a pattern used to define errors and handle them in a (to me) very peculiar way. Often errors are declared like ErrorSomethingWentWrong = errors.New("Just an example!"). You can use errors.Is(err, ErrorSomethingWentWrong) to catch that specific error. The Is function can do this by comparing the pointers. But in order to make the comparison I need to know which variable name is used to define the errorString so I can use errors.Is to catch it.
For example:
ErrorSomethingWentWrong = errors.New("Just an example!")
func DoSomething() (*Something, error) {
return nil, ErrorSomethingWentWrong
}
I know a error is returned with the string "Just an example!" But I don't know it has the variable name ErrorSomethingWentWrong:
func checkError() {
if errors.Is(err, ErrorSomethingWentWrong){ // how to know this???
//handle error
}
}
When I use errors.Is(err, ErrorSomethingWentWrong) I can catch this error and handle it. When using debugging I can't see that the errorString represents the ErrorSomethingWentWrong variable. But when I don't know that the variable name was ErrorSomethingWentWrong I need to reverse engineer the code or read the docs to know which error is returned.
So how can you know using debugging or reflection to retrieve the error variable name?
If I understand correctly, this is your scenario:
You are receiving an error from a package, and there is no documentation to provide you with the errors you should be handling. You are debugging, and see an errors.errorString, but don't know if there is a global and public error value that you can compare to.
Unfortunately, this is a value and the debugger can't tell you if this is a global variable or if so which one, because you don't receive a variable, only a value.
You can:
read through the source code of the package you are calling and see which errors are being returned and how to handle them
search the source code for the text in the error string, this could help you pinpoint where the error is defined or created.
If it turns out the specific error you wish to handle is not defined globally (and re-writing the package is not feasible for your case), so you can't handle it. This can happen if somebody uses errors.New inside a function (bad practice). Then you can also try these:
func handleError(err error) {
if err.Error() == "full error string" {}
if strings.Contains(err.Error(), "partial error string") {}
}
But those are both ugly imho.
TL;DR It's not possible, you have to read the source code.
Right now autodoc seems to throw warnings for any rtype value that is not just an object type (a class instance, int, list, dictionary, etc). So a return value such as "list of tuples" will throw a warning. Is there any way to ignore these warnings (either individually or on the whole)? I don't want to ignore the whole file, just those specific warnings.
An example of this warning might be something like:
/path/to/code.py:docstring of path.to.code.method:: WARNING: py:class reference target not found: list of tuples
And in some cases, I'm seeing errors for objects that I know are legit classes imported in the code like:
/path/to/code.py:docstring of path.to.code.method:: WARNING: py:class reference target not found: Response
In that example, "Response" is part of rest_framework.response, so it's a pretty commonly used class object.
These warnings happen anytime I do a fresh make docs. It's not clear to be that it can be reproduced in another environment.
The solution here was that the classes in question were not in a toctree, so were not part of the docs. Basically, autodocs wants to be able to link to classes mentioned in type variables. If it can't do that, it will throw an error saying "I have no idea what "Response" is (or whatever the class happens to be that you return). Not an error, because it assumed you're right, but a warning that it can't find it. So the solution here was to create an index.rst that included the class, then a Response.rst (for example) including the relative path to the class. Below is an example of this process. It assumes that Response is in a rest.py.
error: /path/to/code.py:docstring of the.code.rest.GetAccount.get:: WARNING: py:class reference target not found: Response
In my case, this needed the following:
add a line item for response to modules/code/rest.rst
add response.rst in the same directory
include the line `.. automodule:: code.rest.Response
Then delete and rebuild docs and it should be good to go.
If a piece of code has its own error type as in
var ErrSomethingWentWrong = errors.New("Something went wrong"
I believe in my code I can do this
import github.com/therepo/theproject/thepackage/thatexportstheaboveerror
// code that might return the above error
if err == thatexportstheaboveerror.ErrSomethingWentWrong {
// handle the particular case
}
What happens when the error returned is via fmt.Errorf as in this case?
return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", keys(tried))
How can value (or type or whatever) check/assertion should be performed go-idiomatically?
Is this the only way around it?
if err != nil {
if strings.Contains(err.Error(), "unable to authenticate") {
// handle the particular error
}
}
Since Go version 1.13, the errors package has included the concept of "wrapping" errors. A routine returning a "wrapped" error calls fmt.Errorf using the %w verb in the format, to wrap an inner error into an outer error. An outer error can then be tested to see if it contains a particular inner error.
Prior to that, xerrors provided the same general concept.
Both of these require that whoever produces the error value use the provided wrapping interface. The routine you are asking about—part of https://godoc.org/golang.org/x/crypto/ssh—does not do this. Some older code that doesn't wrap errors provides certain kind of error-testing functions. For instance, when os.Open returns an error, os.IsNotExist will tell you if that error is because the file does not exist.
Unfortunately this particular package has no such test, so you're pretty much stuck with what you've suggested (direct string inspection) if you really want to know, programmatically, that this error came from this particular source.
Is there any way in Golang for a func to "throws"(like in java) an error?
Through Which I can specify , my func may return error and caller needs to handle the error.
I am just trying to mimic "throws" like approach which we have in java.
May be this is very basic elementary type question , sorry for that , I am new in golang.
Note : I have tried panic, defer, recover , but problem is that if both the functions/methods is in same go file it is working properly , but if suppose both(caller and func) are different go file it is starting a different go routine , "defer" at caller level is not working properly.
I guess this approach is not also equivalent like "throws" , where function provider is not handling the error but caller did that , and take the recovery action. Function body provider just specify it may return some exception and caller have to handle the exception.
Thanks in advance...
No, you cannot do that. Go does not support throwing exceptions.
As you have noticed, you can panic and recover, but it's not the same thing.
I have a service type called ComputeService which implements certain domain logic. The service itself depends on implementation of an interface called Computer which has a method Computer.Compute(args...) (value, error). As shown, Compute itself might return certain errors.
ComputeService needs to send appropriate errors from a set of domain-errors with proper domain-error code so that translations can be done and also clients can handle errors appropriately.
My question is, should the Computer implementations be wrapping their failure in domain-errors or should ComputeService do this. If ComputeService is the one doing it, then it will have to know about different errors returned by different implementations of Computer interface which in my opinion breaks the abstraction. Both ways are demonstrated below:
package arithmetic
type Computer struct {
}
func (ac Computer) Compute(args ....) (value, error) {
// errors is a domain-errors package defined in compute service project
return errors.NewDivideByZero()
}
OR
package compute
type Service struct {
}
func (svc Service) Process(args...) error {
computer := findComputerImplementation(args...)
val, err := computer.Compute(args...)
if err != nil {
if err == arith.ErrDivideByZero {
// converting an arithmetic computer implementation
// specific error to domain error
return errors.NewDivideByZero()
} else if err == algebra.ErrInvalidCoEfficient {
// converting an algebraic computer implementation
// specific error to domain error
return errors.NewBadInput()
}
// some new implementation was used and we have no idea
// what errors it could be returning. so we have to send
// a internal server error equivalent here
return errors.NewInternalError()
}
}
Implementors of Computer should respond with the domain errors, since they're the closest ones to the action and best able to determine what an error is. Like you said, having that logic in ComputeService breaks the abstraction. If you need mapping code from specific Computer errors to domain errors, create wrapper structs that separate the main logic from that error wrapping code.
To keep internal error context, just embed the original error in the domain error and make IsSpecificDomainError helpers.
type MyDomainError struct {
Err error
}
func NewMyDomainErr(err error) error {
return &MyDomainError{err}
}
func IsMyDomainError(e error) bool {
_, ok := err.(*MyDomainError)
return ok
}
To keep internal error context, just embed the original error in the domain error
This can use Wrapping errors, which are on their way for Go 1.13 (Q4 2019), from issue 29934, as detailed here.
err.Is():
As Russ Cox mentions:
I think we all agree that strings.Contains(err.Error(), "not found") is fragile code.
I hope we also agree that we'd prefer to see code like errors.Is(err, os.ErrNotExist).
But the point is that in many cases, it is essential to future evolution of a package to keep callers from depending on a particular error result satisfying errors.Is(err, os.ErrNotExist), even if that is the underlying cause in today's result.
It's like looking at an unexported field or comparing error text - it's a detail that might change.
And while strings.Contains looks and is fragile, errors.Is does not look nor should be considered fragile.
If we are to avoid it being fragile, then we need to provide a way for packages to report detail without letting clients test for it. That way is errors that can't be unwrapped.
err.As():
var pe *os.PathError
if errors.As(err, &pe) {
use(pe)
}
%w:
func inner() error { return errors.New("inner error") }
func outer() error { return fmt.Errorf("outer error: %w", inner()) }
fmt.Fprintf("%+v", outer())
// outer error:
// /path/to/file.go:123
// - inner error:
// /path/to/file.go:122
The current status for Go 1.13:
Just stating what I see as the compromise solution offered by the team:
fmt.Errorf is currently being used extensively to wrap errors and return a new (opaque) error (as in you cannot access the underlying error).
'%w' can now be used to explicitly opt-in to return an error that can be unwrapped.
errors is designed as a base package with no dependencies so that every package can depend on it.
the team agrees to punt on the areas that there is broad disagreement, and want to release just enough (errors.Is, errors.As, extension to way most folks wrap errors) so folks can achieve things.
Generics is not here yet, and we do not know when it will come: the heated discussion on that will make this one on "error 2 values" look like child's play.
errors.Is and errors.As are clean and concise enough to be comfortable for a long time.
Most of the contentious things have been punted to go 1.14.
Wrapf cannot live in errors as it is a base package.
Wrapf means team MUST decide on what happens when a nil error is passed: Punt on it.
Wrap may conflict with ideas being considered for localization, internationalization, etc.
ErrorFormatter and ErrorPrinter have not yet gotten much deeper usage and have warts. Punt.