googleads-python-lib
googleads-python-lib copied to clipboard
Incorrect handling of 401 error response
For a single user, using his refresh token to do the following:
# Using googleads v23.0.1
customerService = adwordsClient.GetService('CustomerService', version='v201809')
accounts = customerService.getCustomers()
We get the following:
Traceback (most recent call last):
File "/home/user/project/.venv/lib/python3.6/site-packages/googleads/common.py", line 992, in MakeSoapRequest
*packed_args, _soapheaders=soap_headers)['body']['rval']
File "/home/user/project/.venv/lib/python3.6/site-packages/zeep/proxy.py", line 45, in __call__
kwargs,
File "/home/user/project/.venv/lib/python3.6/site-packages/zeep/wsdl/bindings/soap.py", line 130, in send
return self.process_reply(client, operation_obj, response)
File "/home/user/project/.venv/lib/python3.6/site-packages/zeep/wsdl/bindings/soap.py", line 195, in process_reply
return self.process_error(doc, operation)
File "/home/user/project/.venv/lib/python3.6/site-packages/zeep/wsdl/bindings/soap.py", line 287, in process_error
detail=etree_to_string(doc),
zeep.exceptions.Fault: Unknown fault occured
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/home/user/project/src/main.py", line 24, in <module>
from jobs.scheduler import scheduleJobs
File "/home/user/project/src/jobs/__init__.py", line 16, in <module>
from api.users import refreshUserEntities
File "/home/user/project/src/api/users.py", line 46, in <module>
from external import adwords_api
File "/home/user/project/src/external/adwords_api/__init__.py", line 1723, in <module>
refreshToken=refreshToken,
File "/home/user/project/.venv/lib/python3.6/site-packages/retrying.py", line 49, in wrapped_f
return Retrying(*dargs, **dkw).call(f, *args, **kw)
File "/home/user/project/.venv/lib/python3.6/site-packages/retrying.py", line 206, in call
return attempt.get(self._wrap_exception)
File "/home/user/project/.venv/lib/python3.6/site-packages/retrying.py", line 247, in get
six.reraise(self.value[0], self.value[1], self.value[2])
File "/home/user/project/.venv/lib/python3.6/site-packages/six.py", line 693, in reraise
raise value
File "/home/user/project/.venv/lib/python3.6/site-packages/retrying.py", line 200, in call
attempt = Attempt(fn(*args, **kwargs), attempt_number, False)
File "/home/user/project/src/external/adwords_api/__init__.py", line 260, in getDirectlyAccessibleAccountsForRefreshToken
accounts = customerService.getCustomers()
File "/home/user/project/.venv/lib/python3.6/site-packages/googleads/common.py", line 997, in MakeSoapRequest
'{%s}ApiExceptionFault' % self._GetBindingNamespace())
TypeError: a bytes-like object is required, not 'str'
The exception object is of type Fault, and contains the following response:
b'<?xml version=\'1.0\' encoding=\'utf-8\'?>\n<HTML>\n<HEAD>\n<TITLE>Unauthorized</TITLE>\n</HEAD>\n<BODY BGCOLOR="#FFFFFF" TEXT="#000000">\n<H1>Unauthorized</H1>\n<H2>Error 401</H2>\n</BODY>\n</HTML>'
I am guessing the API is not returning a proper SOAP response, instead - it is returning an HTML response denoting the error.
I am not sure if the library should handle this, or if the API behavior is invalid.
@wihl Do you have any updates regarding this issue?
It's still appear in the system. Instead of the SOAP XML answer from the Google Ads API server we receive an HTML response with the next body:
<HTML>
<HEAD>
<TITLE>Unauthorized</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Unauthorized</H1>
<H2>Error 401</H2>
</BODY>
</HTML>
Because of this it's an error appeared in the zeep
library that you use. It expects the XML document, but received an HTML document instead with the 401 error. It crashed because of this, and raised exception with zeep.exceptions.Fault: Unknown fault occured
. Then your code caches such exception and tries to check what type of the error appeared, but because it's a bytes string instead of the normal string - it crashes with the next error: TypeError: argument should be integer or bytes-like object, not 'str'
Seems that someone on the Google Ads API side needs to fix the issue. We provide the correct Auth Token, but the user doesn't have any of Google Ads accounts. Seems that this error appears because of this, please check the case.
Used versions of the Python libs:
googleads 28.0.0
googleapis-common-protos 1.53.0
httplib2 0.19.1
urllib3 1.25.11
zeep 4.0.0
We are also getting an HTML response when calling getCurrentNetwork
with a valid auth token:
<HTML>
<HEAD>
<TITLE>Unauthorized</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Unauthorized</H1>
<H2>Error 401</H2>
</BODY>
</HTML>
This is working as intended. Requests without a valid access token will return a 401 response, not a SOAP response.
@christopherseeley An error of type zeep.exceptions.Fault: Unknown fault occured
doesn't seem like a good behavior, I'd expect something related to the 401
Good point, we can look into improving handling of 401's in the library