191

I'm trying to write "good" python and capture a S3 no such key error with this:

session = botocore.session.get_session()
client = session.create_client('s3')
try:
    client.get_object(Bucket=BUCKET, Key=FILE)
except NoSuchKey as e:
    print >> sys.stderr, "no such key in bucket"

But NoSuchKey isn't defined and I can't trace it to the import I need to have it defined.

e.__class__ is botocore.errorfactory.NoSuchKey but from botocore.errorfactory import NoSuchKey gives an error and from botocore.errorfactory import * doesn't work either and I don't want to capture a generic error.

theist
  • 3,270
  • 2
  • 22
  • 23
  • 1
    For exceptions like `botocore.errorfactory.NoSuchKey`, modeled exceptions needs to be accessed through the client object. So rather than having `botocore.errorfactory.NoSuchKey` you need `client.exceptions.NoSuchKey` – simpleuser Feb 27 '21 at 00:59

4 Answers4

225
from botocore.exceptions import ClientError

try:
    response = self.client.get_object(Bucket=bucket, Key=key)
    return json.loads(response["Body"].read())
except ClientError as ex:
    if ex.response['Error']['Code'] == 'NoSuchKey':
        logger.info('No object found - returning empty')
        return dict()
    else:
        raise
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Jose Alban
  • 7,286
  • 2
  • 34
  • 19
  • 1
    I prefer this technique (inspect the error.response dict) because it is more Type friendly compared to the alternative `client.exceptions.NoSuchKey` technique; the python type system has no idea about the class structure of the latter. I am aware of some add-on type annotation solutions but I don't like that approach either, its too much hard work. – hi2meuk Aug 01 '22 at 14:26
  • I found its path when importing aioboto3 (async boto3): aioboto3.session.boto3.exceptions.botocore.errorfactory.ClientError – Cryptc Jun 05 '23 at 19:27
  • I am getting `ex.response['Error']['Code'] == "404"`, is this the same? – Gulzar Jul 16 '23 at 21:27
107

Using botocore 1.5, it looks like the client handle exposes the exception classes:

session = botocore.session.get_session()
client = session.create_client('s3')
try:
    client.get_object(Bucket=BUCKET, Key=FILE)
except client.exceptions.NoSuchKey as e:
    print >> sys.stderr, "no such key in bucket"
groner
  • 2,146
  • 1
  • 16
  • 7
  • I'm opting for this one, as it's newer and also less generic. You can find some comments on GitHub regarding this method: https://github.com/boto/boto3/issues/1262#issuecomment-329314670 – Sylwester Kardziejonek May 03 '18 at 17:03
  • 9
    If you forgot to scroll like me: If you're using the high-level resource (`s3 = boto3.resource("s3")`), you can access the client and thus the Exception via `s3.meta.client.exceptions.NoSuchKey`. See https://stackoverflow.com/questions/38581465/boto3-get-a-resource-from-a-client – Karl Lorey Jul 02 '20 at 16:34
56

In boto3, I was able to access the exception in resource's meta client.

import boto3

s3 = boto3.resource('s3')
s3_object = s3.Object(bucket_name, key)

try:
    content = s3_object.get()['Body'].read().decode('utf-8')
except s3.meta.client.exceptions.NoSuchKey:
    print("no such key in bucket")
Randy
  • 1,498
  • 13
  • 8
44

I think the most elegant way to do this is in Boto3 is

session = botocore.session.get_session()
client = session.create_client('s3')

try:
    client.get_object(Bucket=BUCKET, Key=FILE)
except client.exceptions.NoSuchKey:
    print("no such key in bucket")

The documentation on error handling seems sparse, but the following prints the error codes this works for:

session = botocore.session.get_session()
client = session.create_client('s3')
try:
    try:
        client.get_object(Bucket=BUCKET, Key=FILE)
    except client.exceptions.InvalidBucketName:
        print("no such key in bucket")
except AttributeError as err:
    print(err)

< botocore.errorfactory.S3Exceptions object at 0x105e08c50 > object has no attribute 'InvalidBucketName'. Valid exceptions are: BucketAlreadyExists, BucketAlreadyOwnedByYou, NoSuchBucket, NoSuchKey, NoSuchUpload, ObjectAlreadyInActiveTierError, ObjectNotInActiveTierError

JeffSolo
  • 549
  • 4
  • 4