AttributeError: 'NoneType' object has no attribute '_getter' in sqlalchemy.engine.result

Issue #3481 resolved
Hanno Schlichting
created an issue

Got a Sentry report from a live site today, using SQLAlchemy 1.0.6, PyMySQL 0.6.3 against a Amazon RDS MySQL 5.6 instance.

This happened just once, in a code path that is frequently executed, so it must be some kind of weird state it got in, though I don't know what state that is.

Looking through the issue tracker, this might be related to a new 1.0 feature via issue #3175.

Full traceback:

Stacktrace (most recent call last):

  <removed app code specific stack frames>

  File "sqlalchemy/orm/query.py", line 2445, in first
    ret = list(self[0:1])
  File "sqlalchemy/orm/query.py", line 2281, in __getitem__
    return list(res)
  File "sqlalchemy/orm/loading.py", line 84, in instances
    util.raise_from_cause(err)
  File "sqlalchemy/util/compat.py", line 199, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb)
  File "sqlalchemy/orm/loading.py", line 51, in instances
    for query_entity in query._entities
  File "sqlalchemy/orm/query.py", line 3312, in row_processor
    polymorphic_discriminator=self._polymorphic_discriminator
  File "sqlalchemy/orm/loading.py", line 313, in _instance_processor
    getter = result._getter(col)
  File "sqlalchemy/engine/result.py", line 495, in _getter
    return self._metadata._getter(key)

AttributeError: 'NoneType' object has no attribute '_getter'

The query going into this is a simple:

session.query(SomeModel).filter(SomeModel.pk_column == 'somevalue')
.first()

In the last stackframe, the locals are:

key = Column('some_column', INTEGER(), table=<some_table>)
self = <sqlalchemy.engine.result.ResultProxy object at 0x4aa7e50>

It looks to me like ResultProxy._metadata ends up being None, even after _init_metadata is called. I see a bunch of if self._metadata is None cases in the other functions, so maybe this just needs one of those protections as well.

Comments (4)

  1. Michael Bayer repo owner

    so this is likely just the exception itself being unhelpful; you should have gotten the "this result proxy does not return rows" exception. The initial cause is that MySQL has an occasional issue where the driver emits a SELECT statement but a set of result rows is not returned, that is, not an empty list, but no columns at all. I think it's mostly a MySQL server issue but there might be factors within the drivers also that contribute towards it.

    From that, you've diagnosed correctly that we should put a check around this method when "self._metadata" is none so that we go into the _non_result() codepath.

  2. Michael Bayer repo owner
    • Fixed regression where new methods on :class:.ResultProxy used by the ORM :class:.Query object (part of the performance enhancements of 🎫3175) would not raise the "this result does not return rows" exception in the case where the driver (typically MySQL) fails to generate cursor.description correctly; an AttributeError against NoneType would be raised instead. fixes #3481

    → <<cset ddad19052965>>

  3. Log in to comment