amazonka icon indicating copy to clipboard operation
amazonka copied to clipboard

S3 error matchers don't match anything

Open brendanhay opened this issue 8 years ago • 2 comments

Rather unfortunate. It seems the S3 service definition has completely nonsensical metadata for the errors.

For example attempting to catch _NoSuchBucket will never succeed given the following S3 response:

ServiceError'
    {_serviceAbbrev     = Abbrev "S3"
    , _serviceStatus    = Status {statusCode = 404, statusMessage = "Not Found"}
    , _serviceHeaders   = [...]
    , _serviceCode      = ErrorCode "Not Found"
    , _serviceMessage   = Nothing
    , _serviceRequestId = Just (RequestId "...")
    }

And the current definition for _NoSuchBucket:

_NoSuchBucket = _ServiceError . hasCode "NoSuchBucket"

Given there is no other obvious metadata available, other than to match known error codes such as "Not Found" above, I'm still pondering how best to fix this.

brendanhay avatar Aug 29 '15 12:08 brendanhay

Just got hit by this when trying to check if a key (Object) exists in an S3 bucket. For anyone else who's relatively new to this or is wondering how to handle these errors, you can create a simple lens like this :

    _NotFound :: AsError a => Getting (First ServiceError) a ServiceError
    _NotFound = _MatchServiceError s3 "Not Found"

You'll have to import AsError, Getting, Service Error, s3 and _MatchServiceError from the corresponding amazonka-core, amazonka-* packages.

The handling + request code would look something like : (handling is from Control.Exception.Lens from the lens package, I think amazonka also has a similar function in the amazonka-lens package)

handling _NotFound {- Lambda to handle your exception here -} $ do
    response <- send $ headObject (BucketName bucketName) (ObjectKey key)

In my case, I'm making a headObject call in order to just get the metadata of an object (my goal is to check if the object exists)

kahlil29 avatar Apr 30 '20 13:04 kahlil29

Given that there's a workaround, I'm punting this until after 2.0.

endgame avatar Oct 04 '21 07:10 endgame

About five months ago, a botocore update added HTTP status codes to the S3 service definition:

https://github.com/boto/botocore/blob/c5ddcdbe0d53d1a7027ddfa94de40ae7646bec7e/botocore/data/s3/2006-03-01/service-2.json#L7466

I advanced the botocore pin, regenerated the S3 SDK, and tested it thus:

ghci> Amazonka.runResourceT . trying S3._NoSuchKey . Amazonka.send env $ S3.newGetObject "<redacted>" "nothing"
Left (ServiceError' {abbrev = Abbrev {fromAbbrev = "S3"}, status = Status {statusCode = 404, statusMessage = "Not Found"}, headers = [("x-amz-request-id","<redacted>"),("x-amz-id-2","<redacted>"),("Content-Type","application/xml"),("Transfer-Encoding","chunked"),("Date","Thu, 18 Apr 2024 04:34:43 GMT"),("Server","AmazonS3")], code = ErrorCode "NoSuchKey", message = Just (ErrorMessage {fromErrorMessage = "The specified key does not exist."}), requestId = Just (RequestId {fromRequestId = "<redacted>"})})

Note that it correctly returns a Left instead of throwing an exception.

However, we cannot advance botocore right now because the current generator emits non-compiling SDKs for some services on newer botocore pins. See this comment for the full details.

I'm going to tag this generator and come back to it after the generator gets fixed (which should happen after 2.1).

endgame avatar Apr 18 '24 04:04 endgame

Actually, I can also get a Left using trying S3._NoSuchKey on the released amazonka-2.0.

Here is what S3 is sending these days (from the trace-level log):

[ServiceError] {
  service    = S3
  status     = 404 Not Found
  code       = NoSuchKey
  message    = Just The specified key does not exist.
  request-id = Just <redacted>
}

So I guess this has become fine at some point?

endgame avatar Apr 18 '24 06:04 endgame