Why am I experiencing an intermittent Assertion Error for entities that are created by Cloud NDB when querying from Python2 NDB?

102 views Asked by At

I recently migrated to Cloud NDB and python3 for app engine from Python2 / ndb. I need both versions running at the same time on the same Datastore.

I've found entity.get() for an entity that was created by Cloud NDB it throws an Assertion error about 20% of requests on the python2 service. Is there a way to update the .get() or otherwise to ensure it can pull it from the datastore correctly?

Error thrown

"/base/alloc/tmpfs/dynamic_runtimes/python27g/19fab4ec47735ec6/python27/python27_lib/versions/1/google/appengine/ext/ndb/model.py", line 1234, in _opt_call_to_base_type
    value = _BaseValue(self._call_to_base_type(value))
  File "/base/alloc/tmpfs/dynamic_runtimes/python27g/19fab4ec47735ec6/python27/python27_lib/versions/1/google/appengine/ext/ndb/model.py", line 751, in __init__
    assert not isinstance(b_val, list), repr(b_val)
AssertionError: []

I thought it might be a cache conflict, but there is a problem about 25% of queries

From logs enter image description here

Workaround: The issue still exists but was about to build NDB query to get the entity indirectly by querying Entity.key == key

2

There are 2 answers

0
Chanpols On

Posting this as a community wiki to help other community members that will encounter this kind of issue.

According to your discussion in chat:

The key itself is valid but a .get() on the key produces the error. So as a workaround I can do an ndb query to circle around it and get the entity key

ndb.Key(urlsafe=url_safe_key)

query = Entity.query(Entity.key == key)

obj = query.get()


You may file a feature request in this link and the Product Team will look into it. However there's no ETA for it.

0
Marcelo Busana On

I encountered the same issue here and upon further investigation, I identified a potential source of the problem. In my current record, there is an array field that no longer exists in the model.

For example:

Store(ndb.model):
  name = ndb.StringProperty()
  #holiday_hours = ndb.StringProperty(indexed=False, repeated=True)

In my record, I have Store(name="Test", holiday_hours=[]). When attempting to update the record using the following code:

store = Store.query(...).get()
store.name = "Updated name"
store.put()

I encountered an assertion exception: assert not isinstance(b_val, list), repr(b_val).

However, when I added the holiday_hours field back to the model, the update worked without any exceptions.

The main concern here is that NDB does not provide sufficient exception information and should not raise exceptions in this type of scenario, as it's a NoSQL database.

To troubleshoot this issue, I modified the NDB source code and added logging within the _to_pb function as shown below:

class Model(_NotEqualMixin):

  ...

  def _to_pb(self, pb=None, allow_partial=False, set_key=True):
    """Internal helper to turn an entity into an EntityProto protobuf."""
    if not allow_partial:
      self._check_initialized()
    if pb is None:
      pb = entity_pb.EntityProto()

    if set_key:
      # TODO: Move the key stuff into ModelAdapter.entity_to_pb()?
      self._key_to_pb(pb)

    for unused_name, prop in sorted(self._properties.iteritems()):
      logging.debug('Encoding %s' % prop)  # LOGS THE PROPERTY BEFORE ASSERTION EXCEPTION
      prop._serialize(self, pb, projection=self._projection)

I hope this information proves helpful to you.