influxdb-client-go icon indicating copy to clipboard operation
influxdb-client-go copied to clipboard

How to check for specific types of errors?

Open flyte opened this issue 2 years ago • 8 comments

I want to look up a bucket by name and create it if it doesn't exist. Something like the following pseudocode:

bucket, err := client.BucketsAPI().FindBucketByName(ctx, "mybucket")
if err != nil {
    // How can I check if the bucket was not found, vs any other error?
    if <error is a not-found error> {
        createBucket(ctx, "mybucket")
    } else {
        return fmt.Errorf("error looking up InfluxDB2 bucket: %v", err)
    }
}

flyte avatar Dec 15 '21 11:12 flyte

@flyte, there is no specific error in the client API. Returning error in case of no item is found is the default behavior for server REST API.

vlastahajek avatar Dec 20 '21 15:12 vlastahajek

How should I check for a 404 error from the server then?

flyte avatar Dec 20 '21 15:12 flyte

@rogpeppe FYI for issues with the go client

lesam avatar Dec 20 '21 17:12 lesam

How should I check for a 404 error from the server then?

@flyte , when server sesponds with an error, in most cases, the returned error by client API is http.Error, where you can check status code. However, in the case of FindBucketByName, as a server responds with empty result if name is not found, this method creates new generic error for the API consistency.

vlastahajek avatar Dec 21 '21 16:12 vlastahajek

Sorry, I still don't understand. I appreciate your responses but you're really going to have to spell it out for me I'm afraid.

I recognise that a generic error is returned in this case, so does that mean I can't assert that the bucket was not found as opposed to a connection error, for example?

flyte avatar Dec 21 '21 17:12 flyte

All that means, there is no nice solution for your use-case, unfortunately. We will analyze if there should be some improvement in the API for such cases. So, for now, I would recommend trying to create a bucket in case of an error. In the worst case, you will end up with two connection errors.

vlastahajek avatar Dec 21 '21 18:12 vlastahajek

How should I check for a 404 error from the server then?

when server sesponds with an error, in most cases, the returned error by client API is http.Error, where you can check status code.

The functions in WriteAPIBlocking also appear to be exceptions; see #293.

pabigot avatar Dec 22 '21 17:12 pabigot

For the non-blocking API I've found at least some errors are not http.Error, but rather one of those wrapped by fmt.Errorf(). You can use err.Unwrap and type assertions, but to handle cases where the error may sometimes not be wrapped by fmt.Errorf() this idiom seems more robust:

var nerr net.Error
var herr *http2.Error
var merr *protocol.MetricError
if errors.As(err, &nerr) {
  log.Printf("EC: net.Error (perm=%t): %s", !nerr.Temporary(), nerr.Error())
} else if errors.As(err, &herr) {
  switch herr.StatusCode {
  case 401: // handle unauthorized
    fallthrough
  case 404: // handle not found
    fallthrough
  default:
    log.Printf("EC: http2.Error: %d: %s\n", herr.StatusCode, herr.Error())
  }
} else if errors.As(err, &merr) {
  if errors.Is(merr, protocol.ErrInvalidName) {
    log.Printf("EC: measurement name missing")
  } else {
    log.Printf("EC: MetricError: %s", merr.Error())
  }
} else {
  log.Printf("EC: Unhandled %T: %s", err, err.Error())
}

protocol.MetricError handles some errors detected before any network connection is made.

pabigot avatar Dec 22 '21 17:12 pabigot