Thoughts about error definition and handling

Frank Mueller frank.mueller at canonical.com
Wed Jun 6 16:21:21 UTC 2012


Today the creation of error informations is handled differently. I've tried to compare the pros and cons of the error creation.

1. Return of simple error messages directly created with errors.New().

+ Simple creation.
- Analyzing only by string comparison.
- Embedded additional information hard to retrieve.
- I18N almost impossible.

2. Return of simple error messages containing information as text with fmt.Errorf().

+ Also simple creation.
+ Easy embedding of additional information.
- Analyzing only by string comparison.
- Embedded additional information hard to retrieve.
- I18N almost impossible.

3. Predefinition and returning of error "constants" using 1.

+ Created once and so simple reuse.
+ Easy analyzing by comparison.
- No additional information embeddable.
- I18N almost imposible.

4. Definition of types implementing the error interface.

+ Easy analyzation using type assertions.
+ Easy embedding of additional information.
+ Additional information can be simply retrieved.
+ Simple creation (&MyNotFoundError{myKey}, &BackendInTroubleError{err}, ...).
+ I18N possible by not only using the Error() string but also defining an own interface like I18NError(locale string) string (or other solutions, e.g. type based tables, if I18N is wanted/needed).
- More implementation effort!

Maybe my list is already too biased, you may already see my preference for solution 4. I already started switching my private code base into this direction and it already helps when packages rely on each other. The caller gets better information what has happened. My preference is also to use solution 4 consequently even if there are sometimes internal errors that are only "worth a string". Here a package base type for wrapping could help, like InternalStateError{msg string, err error}. I think this will help us when doing maintenance or extend "foreign" code. 

But I think you may have different ideas and I'm interested in it.

Additionally right now we have different shapes of error messages, some have prefixes (state: and charm:), most not, some start with a capital letter, most not. As Gustavo said with good reason this has to be cleaned. I'll doing it for the state package.

Third part is the passing of low-level errors up to higher level callers. I don't know if it's a problem in other packages too, but in state I've often passed errors to the caller "as is". So even ZooKeeper errors raised to the user of the state package. Error wrapping like solution 4 above will definitely help me internally to check if I have a backend (ZooKeeper) error or if I have a business logic error (entity with key foo-0001 can't be found in topology) and which one it is, so that state API can translate it to user friendly error I'll return with the right additional information (e.g. service name instead of service key).

But as I said, here I don't know how much the third part also concerns you. ;) More interesting to me is if we find a common way of error definition.

mue

--
** Frank Mueller <frank.mueller at canonical.com>
** Software Engineer - Juju Development
** Canonical




More information about the Juju-dev mailing list