I've come across a scenario where in Teleport we attempt to connect to multiple ports to determine where the Proxy is hosted, and, as it stands we return the last error that is encountered if none succeed. This is quite sub-optimal, as it often means that a more useful error (e.g the certificate being self signed) is lost and a less useful error (connection refused) is propagated up to the user.
Returning an aggregate error here would be awesome, but unfortunately, we really lack a way of exploring an error hierarchy once an aggregate
is involved within it. This makes it difficult for a check higher up in the application to say something like:
In this wrapped error, at any point in the chain of wrapped errors, is there an x509.UnknownAuthorityError
?
In an ideal situation, something like the following code would work (it's a little verbose and psuedocodey, but intending to demonstrate that no amount of wrapping/aggregating should obscure an error in the chain):
firstErr := trace.Wrap(flux.NewCapacitorUnderchargedErr())
secondErr := flux.NewBackupCapacitorMissingErr()
err := trace.NewAggregate(firstErr, secondErr)
err := trace.Wrap(err) // simulating the aggregate being wrapped somewhere in callstack
if errors.Is(err, flux.ErrCapacitorUndercharged) {
fmt.Println("Your flux capacitor is undercharged, you may want to try charging it before trying again")
} else {
fmt.Println("We don't have any good advice, the raw error might help: %s\n", err)
}
I believe https://github.com/hashicorp/go-multierror provides a good reference implementation for this sort of behaviour.