Python Social Auth “‘NoneType’ object has no attribute ‘provider'” Issue & Solution

I faced this issue as seen here in http://stackoverflow.com/questions/31591545/using-python-social-auth-the-social-user-is-not-being-set-in-the-pipeline and also in https://github.com/omab/python-social-auth/issues/989.

After debugging through the python social auth code I found that my social_auth_usersocialauth_id_seq value was messed up. I am using PostgreSQL as my database.

Here is what I did to get into the mess. You can see if this is what you did.

  • Dumped the database
  • Kept only the statements that would recreate the
    social_auth_usersocialauth table entries
  • Left out the SELECT
    pg_catalog.setval('social_auth_usersocialauth_id_seq', 365, true);

    statement from the DB dump
  • Ran Django migrate
  • Load the table entries through the dump

I debugged python social auth code to see what’s happening and why the social_user variable is set to None. I saw that the function for pipeline entry associate_user (named  social.pipeline.social_auth.associate_user in python social auth documentation) creates an entry in the table social_auth_usersocialauth and if any exceptions are raised by the DB, they are caught silently and it finally results in the social_user variable being None.

Here is the modified code of this pipeline function in pipeline/social_auth.py:

def associate_user(backend, uid, user=None, social=None, *args, **kwargs):
    if user and not social:
        try:
            social = backend.strategy.storage.user.create_social_auth(
                user, uid, backend.name
            )
        except Exception as err:
            if not backend.strategy.storage.is_integrity_error(err):
                raise
            # Protect for possible race condition, those bastard with FTL
            # clicking capabilities, check issue #131:
            #   https://github.com/omab/django-social-auth/issues/131
            traceback.print_exc()
            return social_user(backend, uid, user, *args, **kwargs)
        else:
            return {'social': social,
                    'user': social.user,
                    'new_association': True}

I just added the line which prints the exception using traceback module. I got this kind of trace when trying to log in a user:

Traceback (most recent call last):
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/social/pipeline/social_auth.py", line 51, in associate_user
    user, uid, backend.name
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/social/storage/django_orm.py", line 125, in create_social_auth
    social_auth = cls.objects.create(user=user, uid=uid, provider=provider)
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/django/db/models/manager.py", line 122, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/django/db/models/query.py", line 401, in create
    obj.save(force_insert=True, using=self.db)
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/django/db/models/base.py", line 700, in save
    force_update=force_update, update_fields=update_fields)
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/django/db/models/base.py", line 728, in save_base
    updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/django/db/models/base.py", line 812, in _save_table
    result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/django/db/models/base.py", line 851, in _do_insert
    using=using, raw=raw)
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/django/db/models/manager.py", line 122, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/django/db/models/query.py", line 1039, in _insert
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 1060, in execute_sql
    cursor.execute(sql, params)
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 79, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/django/db/utils.py", line 95, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/home/reeteshranjan/.virtualenvs/techies/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
IntegrityError: duplicate key value violates unique constraint "social_auth_usersocialauth_pkey"
DETAIL:  Key (id)=(43) already exists.

I checked my database and this is how the social_auth_usersocialauth_id_seq entry looked:

    # \d social_auth_usersocialauth_id_seq
         Sequence "public.social_auth_usersocialauth_id_seq"
        Column     |  Type   |               Value
    ---------------+---------+-----------------------------------
     sequence_name | name    | social_auth_usersocialauth_id_seq
     last_value    | bigint  | 43
     start_value   | bigint  | 1
     increment_by  | bigint  | 1
     max_value     | bigint  | 9223372036854775807
     min_value     | bigint  | 1
     cache_value   | bigint  | 1
     log_cnt       | bigint  | 0
     is_cycled     | boolean | f
     is_called     | boolean | t
    Owned by: public.social_auth_usersocialauth.id

There was a clear problem with the value of last_value. It should be 365 which is the maximum value of id field of the social_auth_usersocialauth in my database.

    # SELECT MAX(id) FROM social_auth_usersocialauth;
     max
    -----
     365
    (1 row)

I dumped my database and found that the social_auth_usersocialauth_id_seq values were indeed messed up in the dump.

# SELECT pg_catalog.setval('social_auth_usersocialauth_id_seq', 43, true);

The value 43 here is the number of failed logins I tried since the DB refresh/reload done using the process mentioned above.

I did this in my database to set the right value for the sequence social_auth_usersocialauth_id_seq:

# SELECT pg_catalog.setval('social_auth_usersocialauth_id_seq', 365, true);

And everything works perfectly after this. I have 6 different social logins in my application – linkedin, github, bitbucket, facebook, twitter, and googleplus. I have verified all of them by logging in using the same account from multiple browsers, then deleting the users and trying the multiple browsers logging in again and everything works fine and as expected.

Advertisements