Update issue with eTag
Environment details
- OS type and version: Mac OS 15
- Python version: Python 3.12.3
- pip version: pip 24.0
google-api-python-clientversion: Version: 2.132.0
Steps to reproduce
When I have to make multiple updates to a contact I fetch the contact to get the etag before making a subsequent update. Its works some of the times but other times it throws a eTag error
googleapiclient.errors.HttpError: <HttpError 400 when requesting https://people.googleapis.com/v1/people/[contactID]:updateContact?updatePersonFields=userDefined&alt=json returned "Request person.etag is different than the current person.etag. Clear local cache and get the latest person.". Details: "Request person.etag is different than the current person.etag. Clear local cache and get the latest person.">
Here is the log for the same contact with the same code succeeding
Found etag: %EgYBAhYuNz0aBAECBQciDGZBTTdOSFZ4QUZnPQ== for contact: BLAH update_body => {'etag': '%EgYBAhYuNz0aBAECBQciDGZBTTdOSFZ4QUZnPQ==', 'userDefined': [{'key': 'Data Quality', 'value': '✅'}, {'key': 'Familiarity', 'value': '⭐️'}, {'key': 'Interests', 'value': '👶Parenting'}]} Fetching contact again!! Found etag: %EgYBAhYuNz0aBAECBQciDGZBTTdOSFZ4QUZnPQ== for contact: BLAH update_body => {'etag': '%EgYBAhYuNz0aBAECBQciDGZBTTdOSFZ4QUZnPQ==', 'userDefined': [{'key': 'Data Quality', 'value': '✅'}, {'key': 'Familiarity', 'value': '⭐️'}, {'key': 'Interests', 'value': '👶Parenting'}, {'key': 'Interests', 'value': '🤖AI'}]} Fetching contact again!! Found etag: %EgYBAhYuNz0aBAECBQciDHJjOWE0SDlpenRrPQ== for contact: BLAH!
Is there some code behind the scenes that caches calls? I always get a new etag once I update it - no issues there. The issue is that this error occurs only sometimes for the same code for the same meta data update. Any help would be greatly appreciated!!
Hi @ajram23, Thanks for reporting this!
Can you provide a code snippet to reproduce this issue?
@ohmayr What code would you like? its python using the API. Here is the line that makes the update: service.people().updateContact(resourceName=resource_name, updatePersonFields=field_person_field, body=update_body_json).execute()
Running into this problem multiple times today.
@ohmayr Do you need anything else?
@ajram23 Can you provide a complete code that you're running? You can hide / replace sensitive information such as project name, etc.
@ohmayr The payload in attached in the initial post and the line of the code that is calling the update is attached above. Curious what else are you looking for?
@ajram23
- What API service name and version are you using?
- Are you configuring any client options? Such as api endpoint, etc?
- How are you defining your request?
From your initial post, it seems like you're trying to fetch a contact and then making an update request. Are these subsequent calls in the same script? Can you provide that?
It will be helpful to have more details around what you're running in order to determine whether this is an issue with the service API or the python client.
@ohmayr Sorry got it. Here are the details
- Python packages google_api_python_client==2.132.0, google_auth_oauthlib==1.2.0
- build('people', 'v1', credentials=creds)
- I am fetching a contact and trying to update custom fields. All of this is done within update_google_contacts function using service.people().updateContact(resourceName=resource_name, updatePersonFields=field_person_field, body=update_body_json).execute()
- I fetch the details of the contact using 262 found_contact = service.people().get(resourceName=resource_id, personFields=person_fields_to_search).execute()
Please let me know if I have missed any other vital details and I will fill you in. Thank you so much for being patient with me, its greatly appreciated!
@ohmayr any updates on this thread? Please and thank you!
Hi @ajram23, apologies for the delay! I was able to reproduce the issue with the following script
# build the service
service = build('people', version="v1", credentials=creds)
count = 1
resourceName = "people/***"
while True:
updated_contact_name = f"testUser{count}"
# fetch the contact to obtain the related eTag
find_contact = service.people().get(resourceName=resourceName, personFields="names").execute()
print("contact found!")
eTag = find_contact['etag']
print("eTag: ", eTag)
# update the contact using the obtained eTag
update_contact = service.people().updateContact(resourceName=resourceName, updatePersonFields="names", body={'etag': eTag, 'names': [{'givenName': name}]}).execute()
count += 1
After a couple of successful iterations of updating the contact name, the script fails at the request to update the contact and results in the following 400 error:
<HttpError 400 when requesting https://people.googleapis.com/v1/people/***:updateContact?updatePersonFields=names&alt=json returned "Request person.etag is different than the current person.etag. Clear local cache and get the latest person.". Details: "[{'@type': 'type.googleapis.com/google.rpc.DebugInfo', 'detail': '[ORIGINAL ERROR] generic::failed_precondition: com.google.social.boq.socialgraph.peopleapis.externalpeopleapi.exceptions.ExternalPreconditionFailedException: Request person.etag is different than the current person.etag. Clear local cache and get the latest person. Code: FAILED_PRECONDITION [google.rpc.error_details_ext] { message: "Request person.etag is different than the current person.etag.>
This is not an issue with the python client and rather a behaviour of the people API when updating the same contact without a delay. If you believe this to be a bug, please file an issue directly with the people API here.
On a side note, I'm able to workaround this issue by implementing retry with exponential backoff in my script i.e.
retry_delay = 1
while True:
try:
# above logic for fetching and updating contact
except Exception as e:
time.sleep(retry_delay)
retry_delay *= 2
retry_delay += random.uniform(0, 1)
Having implemented the retry logic, I'm able to successfully update the same contact sequentially using the above script without a 400 error. You could try implementing a similar retry mechanism to workaround this issue!
Let me know if you have any questions or concerns!
Closing this issue since a workaround was provided in the previous comment as well as next steps to follow up with the API team. Feel free to open a new issue if needed.
Thanks for your help @ohmayr Tried that route only to be told they wont fix it. Pretty lousy user experience but it is what it is. Really appreciate your help!