4655: Crash in user selector widget when avatar data is not available

flipback
david
david

What version are you running?

ReviewBoard 3.0.3

What's the URL of the page containing the problem?

http://10.155.26.78/reviewboard/admin/db/reviews/group/19/

What steps will reproduce the problem?

  1. Create a review group;
  2. Add a user to the group;
  3. Click on the group in the review group table (/reviewboard/admin/db/reviews/group/)

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

I expected to see the group opened to edit, but I see:

Something broke! (Error 500)

What operating system are you using? What browser?

Ubuntu 16.04 LTS, Firefox 58.0.2

Please provide any additional information below.

I started happening after upgrade from 2.5 to 3.0.3.
If a groupd review is empty (doesn't have any users) it works ok.

chipx86
#1 chipx86

Can you check the reviewboard.log for errors? (If you don't have one in your $sitedir/logs/ directory, you may need to enable logging first). There should be a traceback describing where in the code the crash occurred.

  • -New
    +NeedInfo
#2 flipback

There are no errors in logs. Only these messages:

2018-02-21 09:21:50,138 - INFO - - root - Reloading logging settings
2018-02-21 09:24:23,725 - INFO - - root - Reloading logging settings
2018-02-21 09:24:57,219 - INFO - - root - Reloading logging settings

The level of logs is DEBUG.

chipx86
#3 chipx86

Hmm, there should be. How about the Apache error log?

Was logging just now enabled, or was already enabled when the error first occurred?

#4 flipback
  1. Apache says nothing;
  2. Logging had been enabled before I updated reviewboard. I'm sure it works because I saw error messages in the logs when the site can't access Gravatar service.
chipx86
#5 chipx86

Is the 500 on Save, and if you reload the page are you able to view the page? If so, is the user saved when you view it?

Can you go through the exact steps, every entered field and mouse click, so I can attempt an identical repro case?

#6 flipback

No problems:
1. Click on "Review Groups" in Admin Dashboard;
2. Click on "Add Review Group" in Review Groups page;
3. Fill name and display name with "test";
4. Add some user into the group;
5. Click on "Save" and you will be redirected on Review Groups page.
6. Click on group "test' in the table
7. You have Error 500.

I'm sorry if the names of the buttons and pages aren't exact. My interface is translated in Russian partially and I don't know how to change the language.

PS: If you miss step 4 you won't have the error.

chipx86
#7 chipx86

Thanks! Unfortunately I'm not able to reproduce.. I'd need to see a stack trace to know more, but since that's for some reason not appearing in the log, that's not readily accessible.

Something you can temporarily enable is DEBUG = True in $sitedir/conf/settings_local.py. This would turn on some more extensive error pages when encountering a HTTP 500 error. You'd need to set it and then restart Apache, then visit the page to see it. You wouldn't want it on long, as it does impact other aspects of the product, but it should give you some details on where the error is occurring. If you could save the HTML for that page to a file locally and then attach it here as a private attachment (upload and click the lock icon), I'll be able to see it.

#8 flipback

Environment:


Request Method: GET
Request URL: http://10.155.26.78/reviewboard/admin/db/reviews/group/23/

Django Version: 1.6.11
Python Version: 2.7.12
Installed Applications:
[u'corsheaders',
 u'django.contrib.admin',
 u'django.contrib.auth',
 u'django.contrib.contenttypes',
 u'django.contrib.sites',
 u'django.contrib.sessions',
 u'django.contrib.staticfiles',
 u'djblets',
 u'djblets.avatars',
 u'djblets.configforms',
 u'djblets.datagrid',
 u'djblets.extensions',
 u'djblets.features',
 u'djblets.feedview',
 u'djblets.forms',
 u'djblets.gravatars',
 u'djblets.integrations',
 u'djblets.log',
 u'djblets.pipeline',
 u'djblets.recaptcha',
 u'djblets.siteconfig',
 u'djblets.util',
 u'haystack',
 u'oauth2_provider',
 u'pipeline',
 u'reviewboard',
 u'reviewboard.accounts',
 u'reviewboard.admin',
 u'reviewboard.attachments',
 u'reviewboard.avatars',
 u'reviewboard.changedescs',
 u'reviewboard.diffviewer',
 u'reviewboard.extensions',
 u'reviewboard.hostingsvcs',
 u'reviewboard.integrations',
 u'reviewboard.notifications',
 u'reviewboard.oauth',
 u'reviewboard.reviews',
 u'reviewboard.scmtools',
 u'reviewboard.site',
 u'reviewboard.webapi',
 u'django_evolution',
 u'rbintegrations']
Installed Middleware:
[u'django.middleware.gzip.GZipMiddleware',
 u'reviewboard.admin.middleware.InitReviewBoardMiddleware',
 u'corsheaders.middleware.CorsMiddleware',
 u'django.middleware.clickjacking.XFrameOptionsMiddleware',
 u'django.middleware.common.CommonMiddleware',
 u'django.middleware.http.ConditionalGetMiddleware',
 u'django.middleware.locale.LocaleMiddleware',
 u'django.contrib.sessions.middleware.SessionMiddleware',
 u'django.contrib.auth.middleware.AuthenticationMiddleware',
 u'django.contrib.messages.middleware.MessageMiddleware',
 u'djblets.siteconfig.middleware.SettingsMiddleware',
 u'reviewboard.admin.middleware.LoadSettingsMiddleware',
 u'djblets.extensions.middleware.ExtensionsMiddleware',
 u'djblets.integrations.middleware.IntegrationsMiddleware',
 u'djblets.log.middleware.LoggingMiddleware',
 u'reviewboard.accounts.middleware.TimezoneMiddleware',
 u'reviewboard.admin.middleware.CheckUpdatesRequiredMiddleware',
 u'reviewboard.admin.middleware.X509AuthMiddleware',
 u'reviewboard.site.middleware.LocalSiteMiddleware',
 u'djblets.extensions.middleware.ExtensionsMiddlewareRunner',
 u'reviewboard.admin.middleware.ExtraExceptionInfoMiddleware']


Traceback:
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
  137.                 response = response.render()
File "/usr/local/lib/python2.7/dist-packages/django/template/response.py" in render
  105.             self.content = self.rendered_content
File "/usr/local/lib/python2.7/dist-packages/django/template/response.py" in rendered_content
  82.         content = template.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  140.             return self._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in _render
  134.         return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  840.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render_node
  854.         return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py" in render
  123.         return compiled_parent._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in _render
  134.         return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  840.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render_node
  854.         return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py" in render
  123.         return compiled_parent._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in _render
  134.         return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  840.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render_node
  854.         return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py" in render
  62.             result = block.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  840.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render_node
  854.         return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py" in render
  62.             result = block.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  840.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render_node
  854.         return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py" in render
  62.             result = block.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  840.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render_node
  854.         return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py" in render
  203.                     nodelist.append(node.render(context))
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py" in render
  155.         return self.render_template(self.template, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py" in render_template
  137.         output = template.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  140.             return self._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in _render
  134.         return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  840.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render_node
  854.         return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py" in render
  203.                     nodelist.append(node.render(context))
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py" in render
  203.                     nodelist.append(node.render(context))
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py" in render
  305.                 return nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  840.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render_node
  854.         return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py" in render
  305.                 return nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  840.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render_node
  854.         return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  897.         return render_value_in_context(output, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render_value_in_context
  875.     value = force_text(value)
File "/usr/local/lib/python2.7/dist-packages/django/utils/encoding.py" in force_text
  100.                 s = s.__unicode__()
File "/usr/local/lib/python2.7/dist-packages/django/forms/forms.py" in __str__
  425.         return self.as_widget()
File "/usr/local/lib/python2.7/dist-packages/django/forms/forms.py" in as_widget
  475.         return widget.render(name, self.value(), attrs=attrs)
File "/usr/local/lib/python2.7/dist-packages/reviewboard/admin/form_widgets.py" in render
  102.                 )['1x']

Exception Type: KeyError at /reviewboard/admin/db/reviews/group/23/
Exception Value: u'1x'
chipx86
#9 chipx86

Thanks! That's very helpful. So there's definitely a bug here, and we'll be able to get a fix for this in for the next release (targetting next Tuesday).

This is happening because no avatar data is being returned for one of the users in the group, and it's breaking the widget, which is assuming the presence of an avatar. You can address this by having an avatar configured for that user, or (temporarily) turning off avatars while configuring the group. Not great, but at least there's a workaround.

#10 flipback

Sorry, I read you message in rush. Here is the html file.

  • +
    <!DOCTYPE html>
    <html lang="en"><script>(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
    (function (global){
    'use strict';
    /*global Web3*/
    cleanContextForImports();
    _dereq_('web3/dist/web3.min.js');
    var log = _dereq_('loglevel');
    var LocalMessageDuplexStream = _dereq_('post-message-stream');
    // const PingStream = require('ping-pong-stream/ping')
    // const endOfStream = require('end-of-stream')
    var setupDappAutoReload = _dereq_('./lib/auto-reload.js');
    var MetamaskInpageProvider = _dereq_('./lib/inpage-provider.js');
    restoreContextAfterImports();
#11 flipback

Ok. Thanks!

chipx86
#12 chipx86
  • -NeedInfo
    +Confirmed
  • +Release-3.0.x
  • -Priority:Medium
    +Component:Admin
    +Component:Avatars
    +Component:Avatars
    +Priority:High
  • -Error 500 occurs if one try to access to a revie group
    +Crash in user selector widget when avatar data is not available
  • +david
david
#13 david

Fixed in release-3.0.x (b616ff3). This will ship in 3.0.4. Thanks!

  • -Confirmed
    +Fixed