Defect #35174

Internal Error when accessing the home page of some projects

Added by Miguel Moquillon 19 days ago. Updated 17 days ago.

Status:Needs feedbackStart date:
Priority:NormalDue date:
Assignee:-% Done:

0%

Category:Projects
Target version:-
Resolution: Affected version:4.2.1

Description

Since the upgrade from 4.1.2 to 4.2.0 and 4.2.1, when accessing the home page of some of our projects, we have an "Internal Error" page with the following error messages in the log:

ActionView::Template::Error (comparison of NilClass with User failed):
    2:   <div class="members box">
    3:     <h3 class="icon icon-group"><%=l(:label_member_plural)%></h3>
    4:     <% @principals_by_role.keys.sort.each do |role| %>
    5:       <p><span class="label"><%= role %>:</span> <%= @principals_by_role[role].sort.collect{|p| link_to_user p}.join(", ").html_safe %></p>
    6:     <% end %>
    7:   </div>
    8:   <% end %>

app/views/projects/_members_box.html.erb:5:in `sort'
app/views/projects/_members_box.html.erb:5:in `block in _app_views_projects__members_box_html_erb___1165424576507768033_82920'
app/views/projects/_members_box.html.erb:4:in `each'
app/views/projects/_members_box.html.erb:4:in `_app_views_projects__members_box_html_erb___1165424576507768033_82920'
app/views/projects/show.html.erb:132:in `_app_views_projects_show_html_erb___1481690599684784851_82880'
lib/redmine/sudo_mode.rb:61:in `sudo_mode'

Note: not all the projects are concerned by this problem.

redmine-Internal_error_page.png - Internal Error HTML page (13.5 KB) Miguel Moquillon, 2021-04-27 16:03

redmine-internal_errror_page.log - Part of the log relative to the Internal Error (1.44 KB) Miguel Moquillon, 2021-04-27 16:10

History

#1 Updated by Marius BALTEANU 19 days ago

I cannot reproduce it, can you tell us more about your environment? Please see Submissions.

#2 Updated by Marius BALTEANU 19 days ago

  • Status changed from New to Needs feedback

#3 Updated by Miguel Moquillon 18 days ago

Operating system: Ubuntu 20.04.2 LTS

ruby bin/about gives:

sh: 1: svn: not found
sh: 1: hg: not found
sh: 1: cvs: not found
sh: 1: bzr: not found
Environment:
  Redmine version                4.2.1.stable
  Ruby version                   2.7.2-p137 (2020-10-01) [x86_64-linux]
  Rails version                  5.2.5
  Environment                    production
  Database adapter               Mysql2
  Mailer queue                   ActiveJob::QueueAdapters::AsyncAdapter
  Mailer delivery                smtp
SCM:
  Git                            2.25.1
  Filesystem                     
Redmine plugins:
  no plugin installed

Our redmine instance is served by Apache2 through passenger: Phusion Passenger(R) 6.0.8

For information, redmine is used since 2010 and was updated at each new release by following the page RedmineUpdate

#4 Updated by Mizuki ISHIKAWA 18 days ago

I implemented this code on the assumption that @principals_by_role[role] is an array containing only User records, but in Redmine where the problem occurred, @principals_by_role[role] seems to have been an array containing user records and nil.

Example:

pry(main)> [User.first, nil, User.second].sort
ArgumentError: comparison of NilClass with User failed
from (pry):18:in `sort'


I think the problem can be solved by changing the code as follows.

diff --git a/app/views/projects/_members_box.html.erb b/app/views/projects/_members_box.html.erb
index e915ab910a..280f2e3aff 100644
--- a/app/views/projects/_members_box.html.erb
+++ b/app/views/projects/_members_box.html.erb
@@ -2,7 +2,7 @@
   <div class="members box">
     <h3 class="icon icon-group"><%=l(:label_member_plural)%></h3>
     <% @principals_by_role.keys.sort.each do |role| %>
-      <p><span class="label"><%= role %>:</span> <%= @principals_by_role[role].sort.collect{|p| link_to_user p}.join(", ").html_safe %></p>
+      <p><span class="label"><%= role %>:</span> <%= @principals_by_role[role].compact.sort.collect{|p| link_to_user p}.join(", ").html_safe %></p>
     <% end %>
   </div>
   <% end %>

#5 Updated by Mizuki ISHIKAWA 18 days ago

I don't know why nil is included, I think it needs improvement if it can happen in other environments.

#6 Updated by Pavel Rosický 18 days ago

Miguel - could you check that you don't have any orphan project members?

rails c -e production
Member.where.not(user_id: Principal.select(:id)).any?

it should return "false"

this could happen by bypassing Redmine's API and removing a user directly from the database. Any chance you did something like this in the past?

#7 Updated by Miguel Moquillon 18 days ago

Pavel Rosický wrote:

Miguel - could you check that you don't have any orphan project members?
[...]
it should return "false"

this could happen by bypassing Redmine's API and removing a user directly from the database. Any chance you did something like this in the past?

Unfortunately, it returns ... "true".
No, we don't use the Redmine's API to do admin tasks (or it should have been a long time ago). What does mean "orphan project member"? A user that is yet a member of a project but whose account has been deleted?

#8 Updated by Miguel Moquillon 18 days ago

Ok, by issuing

Member.select(:user_id).where.not(user_id: Principal.select(:id)).distinct

I found the identifier of the user causing the error (I'm not a ruby programmer but I figured out the instruction from your code snippet): there is only one user (an old one).

Can I remove it from the membership of the projects without any consequences by executing the following code (is the code correct?):

Member.delete.where(user_id: 6)

#9 Updated by Pavel Rosický 18 days ago

if you remove a user from the system, all dependencies like project members are deleted via callbacks
https://github.com/redmine/redmine/blob/master/app/models/principal.rb#L31

however, if you bypass the API, you end up in a situation there's a member entry that refers to a user which doesn't exist in the `users` table.

Mizuki ISHIKAWA's solution is only fixing the consequences of the database inconsistency.

btw: foreign key constraints in the schema should prohibit such actions on the database level, but Redmine doesn't use them, see https://www.redmine.org/boards/4/topics/65243

#10 Updated by Miguel Moquillon 18 days ago

Pavel Rosický wrote:

if you remove a user from the system, all dependencies like project members are deleted via callbacks
https://github.com/redmine/redmine/blob/master/app/models/principal.rb#L31

however, if you bypass the API, you end up in a situation there's a member entry that refers to a user which doesn't exist in the `users` table.

Mizuki ISHIKAWA's solution is only fixing the consequences of the database inconsistency.

btw: foreign key constraints in the schema should prohibit such actions on the database level, but Redmine doesn't use them, see https://www.redmine.org/boards/4/topics/65243

Ok. When I wrote we don't use the Redmine's API, I means we use the Redmine administration page for doing such tasks. (In my mind, Redmine API were meaning REST API.)

#11 Updated by Pavel Rosický 18 days ago

Can I remove it?

you should do a backup first before such actions. But each member should refer to an existing user.

#12 Updated by Pavel Rosický 18 days ago

it's hard to guess, how this could happen in your environment. If it used to work in the previous version and you have a backup, try to compare the data, when the user was removed and how...

#13 Updated by Miguel Moquillon 17 days ago

Pavel Rosický wrote:

Can I remove it?

you should do a backup first before such actions. But each member should refer to an existing user.

Backup of our redmine installation (with database) are performed every night. So in the morning I purged the memberships of the deleted old user by issuing the following command:

Member.where(user_id: 6).destroy_all

According to the Rails documentation, destroy_all triggers the execution of all the callbacks of the objects.

Once done, we haven't anymore the internal error when accessing the projects' home page.

#14 Updated by Miguel Moquillon 17 days ago

Pavel Rosický wrote:

it's hard to guess, how this could happen in your environment. If it used to work in the previous version and you have a backup, try to compare the data, when the user was removed and how...

Unfortunately, we don't keep our backups a long time; we purged them every month.

Also available in: Atom PDF