Search code examples
pythongoogle-cloud-platformgoogle-cloud-storagegoogle-cloud-python

How to access error reason in Python google.cloud.storage upload methods?


I am using Google's google-cloud-storage Python package for GCS access. When I get a 403 error it could be for many different reasons. Google's SDK by default only provides this message:

('Request failed with status code', 403, 'Expected one of', <HTTPStatus.OK: 200>)")

Using a debugger I can look deeper into the library and find _upload.py has a _process_response method where the true HTTP response can be found, with the following message as part of the result:

"message": "$ACCOUNT does not have storage.objects.delete access to $BLOB."

Q: Is there any way I can access this more useful error code or the raw response?

I am hoping to present to the user the difference between e.g. expired credentials and attempting to do something your credentials do not allow.


Solution

  • What version of google-cloud-storage are you using? With the latest, and this example:

    from google.cloud import storage
    client = storage.Client.from_service_account_json('service-account.json')
    bucket = client.get_bucket('my-bucket-name')
    blob = bucket.get_blob('test.txt')
    try:
        blob.delete()
    except Exception as e:
        print(e)
    

    It prints the following:

    403 DELETE https://storage.googleapis.com/storage/v1/b/my-bucket-name/o/test.txt?generation=1579627133414449: $ACCOUNT does not have storage.objects.delete access to my-bucket-name/test.txt.

    The string representation here is roughly the same as e.message:

    >>> e.message
    'DELETE https://storage.googleapis.com/storage/v1/b/my-bucket-name/o/test.txt?generation=1579627133414449: $ACCOUNT does not have storage.objects.delete access to my-bucket-name/test.txt.'
    

    If you want more structure, you can use e._response.json():

    >>> e._response.json()
    {
        'error': {
            'code': 403,
            'message': '$ACCOUNT does not have storage.objects.delete access to my-bucket-name/test.txt/test.txt.',
            'errors': [{
                'message': '$ACCOUNT does not have storage.objects.delete access to my-bucket-name/test.txt/test.txt.',
                'domain': 'global',
                'reason': 'forbidden'
            }]
        }
    }