Issue 700 in gdata-python-client: Doing a batched delete of contacts always returns "If-Match or If-None-Match header or entry etag attribute required" error

35 views
Skip to first unread message

gdata-pyt...@googlecode.com

unread,
May 28, 2014, 4:19:25 AM5/28/14
to gdata-python-client-...@googlegroups.com
Status: New
Owner: ----
Labels: Type-Defect Priority-Medium

New issue 700 by joh...@gmail.com: Doing a batched delete of contacts
always returns "If-Match or If-None-Match header or entry etag attribute
required" error
http://code.google.com/p/gdata-python-client/issues/detail?id=700

What steps will reproduce the problem?
1. Prepare a ContactsFeed with contacts to be deleted

request_feed = gdata.contacts.data.ContactsFeed()
request_feed.AddDelete(entry=contact, batch_id_string='delete')

2. Perform ExecuteBatch

response_feed = self.gd_client.ExecuteBatch(
request_feed,
'https://www.google.com/m8/feeds/contacts/default/full/batch'
)


What is the expected output? What do you see instead?

Expected output would be for the contacts to be deleted. Instead a 403
response with message "If-Match or If-None-Match header or entry etag
attribute required" is returned.

Even with the recommended workaround of adding the "If-Match: *" header
doesn't work:

custom_headers = atom.client.CustomHeaders(**{'If-Match': '*'})
request_feed = gdata.contacts.data.ContactsFeed()
request_feed.AddDelete(entry=contact, batch_id_string='delete')
response_feed = self.gd_client.ExecuteBatch(
request_feed,
'https://www.google.com/m8/feeds/contacts/default/full/batch'
)


What version of the product are you using?

gdata 2.0.18

Please provide any additional information below.

Not sure if it's related, but this started happening when Google required
the "Contacts API" entry in the Cloud Console UI to be enabled. Before,
there was no entry for "Contacts API" in the Cloud Console UI, so I guess
it was enabled by default. But after being added, and it was set to
Disabled by default, things started breaking.

Other discussions on StackOverflow:
http://stackoverflow.com/questions/23757499/if-match-or-if-none-match-header-or-entry-etag-attribute-required-error-while-up
http://stackoverflow.com/questions/2989257/if-match-or-if-none-match-header-or-entry-etag-attribute-required-error-when-t?rq=1
http://stackoverflow.com/questions/23576729/getting-if-match-or-if-none-match-header-or-entry-etag-attribute-required-erro

--
You received this message because this project is configured to send all
issue notifications to this address.
You may adjust your notification preferences at:
https://code.google.com/hosting/settings

gdata-pyt...@googlecode.com

unread,
May 28, 2014, 9:59:44 PM5/28/14
to gdata-python-client-...@googlegroups.com

Comment #1 on issue 700 by joh...@gmail.com: Doing a batched delete of
contacts always returns "If-Match or If-None-Match header or entry etag
attribute required" error
http://code.google.com/p/gdata-python-client/issues/detail?id=700

Using the `Batch` method with `force=True` is the same result.

response_feed = self.gd_client.Batch(
request_feed,
uri='https://www.google.com/m8/feeds/contacts/default/full/batch',
force=True
)

gdata-pyt...@googlecode.com

unread,
Jun 3, 2014, 11:22:12 AM6/3/14
to gdata-python-client-...@googlegroups.com

Comment #2 on issue 700 by joh...@gmail.com: Doing a batched delete of
contacts always returns "If-Match or If-None-Match header or entry etag
attribute required" error
http://code.google.com/p/gdata-python-client/issues/detail?id=700

There is a typo on the first code snippet (missing custom_headers param).
Should read:

custom_headers = atom.client.CustomHeaders(**{'If-Match': '*'})
request_feed = gdata.contacts.data.ContactsFeed()
request_feed.AddDelete(entry=contact, batch_id_string='delete')
response_feed = self.gd_client.ExecuteBatch(
request_feed,
'https://www.google.com/m8/feeds/contacts/default/full/batch',
custom_headers=custom_headers

gdata-pyt...@googlecode.com

unread,
Jun 21, 2014, 2:41:05 PM6/21/14
to gdata-python-client-...@googlegroups.com

Comment #3 on issue 700 by administ...@eforcers.com.co: Doing a batched
delete of contacts always returns "If-Match or If-None-Match header or
entry etag attribute required" error
http://code.google.com/p/gdata-python-client/issues/detail?id=700

im having the same issue

gdata-pyt...@googlecode.com

unread,
Jun 22, 2014, 3:59:28 AM6/22/14
to gdata-python-client-...@googlegroups.com

Comment #4 on issue 700 by alexandr...@gmail.com: Doing a batched delete of
contacts always returns "If-Match or If-None-Match header or entry etag
attribute required" error
http://code.google.com/p/gdata-python-client/issues/detail?id=700

Same here.

gdata-pyt...@googlecode.com

unread,
Jun 28, 2014, 3:08:19 PM6/28/14
to gdata-python-client-...@googlegroups.com

Comment #5 on issue 700 by tsarfaty...@gmail.com: Doing a batched delete of
contacts always returns "If-Match or If-None-Match header or entry etag
attribute required" error
http://code.google.com/p/gdata-python-client/issues/detail?id=700

same - having the same issue. there is a solution?

gdata-pyt...@googlecode.com

unread,
Jun 30, 2014, 11:03:40 PM6/30/14
to gdata-python-client-...@googlegroups.com

Comment #6 on issue 700 by joseph.d...@gmail.com: Doing a batched delete of
contacts always returns "If-Match or If-None-Match header or entry etag
attribute required" error
http://code.google.com/p/gdata-python-client/issues/detail?id=700

I've been digging at it for a few hours, no progress yet. Here's a sample
request feed:

<ns0:feed xmlns:ns0="http://www.w3.org/2005/Atom"
xmlns:ns1="http://schemas.google.com/g/2005"
xmlns:ns2="http://schemas.google.com/contact/2008"
xmlns:ns3="http://schemas.google.com/gdata/batch"
xmlns:ns4="http://www.w3.org/2007/app">
<ns0:entry ns1:etag="&quot;<id>&quot;">
<ns2:groupMembershipInfo deleted="false"
href="http://www.google.com/m8/feeds/groups/<user_email>/base/6"/>
<ns2:groupMembershipInfo deleted="false"
href="http://www.google.com/m8/feeds/groups/<user_email>/base/<id>"/>

<ns0:id>http://www.google.com/m8/feeds/contacts/<user_email>/base/<id></ns0:id>
<ns1:name>
<ns1:fullName>Test Two</ns1:fullName>
<ns1:familyName>Two</ns1:familyName>
<ns1:givenName>Test</ns1:givenName>
</ns1:name>
<ns0:category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/contact/2008#contact"/>
<ns0:title>Test Two</ns0:title>
<ns0:updated>2014-06-30T22:13:48.049Z</ns0:updated>
<ns3:id>delete</ns3:id>
<ns3:operation type="delete"/>
<ns0:link
href="https://www.google.com/m8/feeds/photos/media/<user_email>/<id>"
rel="http://schemas.google.com/contacts/2008/rel#photo" type="image/*"/>
<ns0:link
href="https://www.google.com/m8/feeds/contacts/<user_email>/full/<id>"
rel="self" type="application/atom+xml"/>
<ns0:link
href="https://www.google.com/m8/feeds/contacts/<user_email>/full/<id"
rel="edit" type="application/atom+xml"/>
<ns4:edited>2014-06-30T22:13:48.049Z</ns4:edited>
</ns0:entry>
<ns0:entry ns1:etag="&quot;<id>&quot;">
<ns2:groupMembershipInfo deleted="false"
href="http://www.google.com/m8/feeds/groups/<user_email>/base/6"/>
<ns2:groupMembershipInfo deleted="false"
href="http://www.google.com/m8/feeds/groups/<user_email>/base/<id>"/>

<ns0:id>http://www.google.com/m8/feeds/contacts/<user_email>/base/<id></ns0:id>
<ns1:name>
<ns1:fullName>Test One</ns1:fullName>
<ns1:familyName>One</ns1:familyName>
<ns1:givenName>Test</ns1:givenName>
</ns1:name>
<ns0:category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/contact/2008#contact"/>
<ns0:title>Test One</ns0:title>
<ns0:updated>2014-06-30T22:13:44.164Z</ns0:updated>
<ns3:id>delete</ns3:id>
<ns3:operation type="delete"/>
<ns0:link
href="https://www.google.com/m8/feeds/photos/media/<user_email>/<id>"
rel="http://schemas.google.com/contacts/2008/rel#photo" type="image/*"/>
<ns0:link
href="https://www.google.com/m8/feeds/contacts/<user_email>/full/<id>"
rel="edit" type="application/atom+xml"/>
<ns4:edited>2014-06-30T22:13:44.164Z</ns4:edited>
</ns0:entry>
</ns0:feed>

gdata-pyt...@googlecode.com

unread,
Jul 1, 2014, 6:47:18 AM7/1/14
to gdata-python-client-...@googlegroups.com

Comment #7 on issue 700 by jahny.t...@gmail.com: Doing a batched delete of
contacts always returns "If-Match or If-None-Match header or entry etag
attribute required" error
http://code.google.com/p/gdata-python-client/issues/detail?id=700

I had the same problem, but i found (few days ago), that if you replace in
request feed the namespace prefix of
xmlns:ns1="http://schemas.google.com/g/2005" to 'gd' (ns1 > gd), it's
working.
You can try it in OAuth 2.0 Playground.

gdata-pyt...@googlecode.com

unread,
Jul 1, 2014, 9:39:00 PM7/1/14
to gdata-python-client-...@googlegroups.com

Comment #8 on issue 700 by joseph.d...@gmail.com: Doing a batched delete of
contacts always returns "If-Match or If-None-Match header or entry etag
attribute required" error
http://code.google.com/p/gdata-python-client/issues/detail?id=700

Thanks, that worked! I ended up making a modification to gdata/client.py, I
couldn't figure out a better way to override it from my own code. I'll have
to do some more testing to make sure it doesn't hurt anything. It should
get me by for now. Here's the change:

In data/client.py:

def post(self, entry, uri, auth_token=None, converter=None,
desired_class=None, **kwargs):
if converter is None and desired_class is None:
desired_class = entry.__class__
http_request = atom.http_core.HttpRequest()
+ entry_string = entry.to_string(get_xml_version(self.api_version))
+ entry_string = entry_string.replace('ns1', 'gd')
http_request.add_body_part(
- entry.to_string(get_xml_version(self.api_version)),
+ entry_string,
'application/atom+xml')
return self.request(method='POST', uri=uri, auth_token=auth_token,
http_request=http_request, converter=converter,
desired_class=desired_class, **kwargs)

gdata-pyt...@googlecode.com

unread,
Jul 16, 2014, 10:21:07 AM7/16/14
to gdata-python-client-...@googlegroups.com

Comment #9 on issue 700 by j...@collabspot.com: Doing a batched delete of
contacts always returns "If-Match or If-None-Match header or entry etag
attribute required" error
http://code.google.com/p/gdata-python-client/issues/detail?id=700

@joseph, Thanks, your patch seems to work for me as well. Will do more
tests. To keep from modifying gdata/client.py, I did this instead:

def patched_post(client, entry, uri, auth_token=None, converter=None,
desired_class=None, **kwargs):
if converter is None and desired_class is None:
desired_class = entry.__class__
http_request = atom.http_core.HttpRequest()
entry_string =
entry.to_string(gdata.client.get_xml_version(client.api_version))
entry_string = entry_string.replace('ns1', 'gd')
http_request.add_body_part(
entry_string,
'application/atom+xml')
return client.request(method='POST', uri=uri, auth_token=auth_token,
http_request=http_request,
converter=converter,
desired_class=desired_class, **kwargs)

# when it comes time to do a batched delete/update,
# instead of calling client.ExecuteBatch, I instead directly call
patched_post
patched_post(my_client_instance, request_feed,
'https://www.google.com/m8/feeds/contacts/default/full/batch')

gdata-pyt...@googlecode.com

unread,
Jul 18, 2014, 5:40:45 PM7/18/14
to gdata-python-client-...@googlegroups.com

Comment #10 on issue 700 by the.matr...@gmail.com: Doing a batched delete
of contacts always returns "If-Match or If-None-Match header or entry etag
attribute required" error
http://code.google.com/p/gdata-python-client/issues/detail?id=700

> entry_string.replace('ns1', 'gd')

Is this the correct way to solve the problem?
It will indiscriminately replace all occurrences of 'ns1' from the anywhere
in the string representation of the entry, including its user-submitted
data fields.

gdata-pyt...@googlecode.com

unread,
Jul 18, 2014, 6:02:35 PM7/18/14
to gdata-python-client-...@googlegroups.com

Comment #11 on issue 700 by the.matr...@gmail.com: Doing a batched delete
of contacts always returns "If-Match or If-None-Match header or entry etag
attribute required" error
http://code.google.com/p/gdata-python-client/issues/detail?id=700

Ideally this problem can be fixed in Google's server-side parser code.

<ns0:feed xmlns:ns1="http://schemas.google.com/g/2005" ns1:etag="foobar">

is semantically equivalent to

<ns0:feed xmlns:gd="http://schemas.google.com/g/2005" gd:etag="foobar">

No?

gdata-pyt...@googlecode.com

unread,
Jul 18, 2014, 8:27:40 PM7/18/14
to gdata-python-client-...@googlegroups.com

Comment #12 on issue 700 by joh...@gmail.com: Doing a batched delete of
contacts always returns "If-Match or If-None-Match header or entry etag
attribute required" error
http://code.google.com/p/gdata-python-client/issues/detail?id=700

Yes, ideally Google fix it server side. But until then, this is the best we
got. But yes, maybe it should be:

entry_string.replace('ns1=', 'gd=').replace('ns1:', 'gd:')

gdata-pyt...@googlecode.com

unread,
Aug 29, 2014, 1:02:43 PM8/29/14
to gdata-python-client-...@googlegroups.com

Comment #13 on issue 700 by james.ch...@rightster.com: Doing a batched
delete of contacts always returns "If-Match or If-None-Match header or
entry etag attribute required" error
https://code.google.com/p/gdata-python-client/issues/detail?id=700

Each entry in the feed requires an etag for verification of the resource
version (https://developers.google.com/gdata/docs/2.0/reference).

The solution is to do a query first to return the etags for your feed, then
add the respective etags to the update feed.

def make_batch_post_request(spreadsheets_client, feed):
self = spreadsheets_client
import atom
http_request = atom.http_core.HttpRequest()
http_request.add_body_part(

feed.to_string(get_xml_version(self.api_version)).replace('update', 'query'),
'application/atom+xml')
auth_token = spreadsheets_client.auth_token
uri = feed.find_edit_link()
response = self.request('POST', uri=uri, auth_token=auth_token,
http_request=http_request, desired_class=feed.__class__)

# <magic>
for index, entry in enumerate(feed.entry):
feed.entry[index].etag = response.entry[index].etag
#</magic>

http_request = atom.http_core.HttpRequest()
http_request.add_body_part(
feed.to_string(get_xml_version(self.api_version)),
'application/atom+xml')
auth_token = spreadsheets_client.auth_token
uri = feed.find_edit_link()
response = self.request('POST', uri=uri, auth_token=auth_token,
http_request=http_request, desired_class=feed.__class__)

return response

gdata-pyt...@googlecode.com

unread,
Mar 2, 2015, 2:57:14 AM3/2/15
to gdata-python-client-...@googlegroups.com

Comment #14 on issue 700 by Un4getta...@gmail.com: Doing a batched delete
of contacts always returns "If-Match or If-None-Match header or entry etag
attribute required" error
https://code.google.com/p/gdata-python-client/issues/detail?id=700

@joseph Thanks, your patch is working :-)
Reply all
Reply to author
Forward
0 new messages