Git 挂起以及管理员/版主账户出现“Oops”错误页面

ActionView::Template::Error(无法将 Array 隐式转换为 String)

我重现了登录时出现的 Oops Page 错误 问题。该问题似乎仅影响管理员账户,在某些情况下也会影响其他工作人员账户,但在此案例中涉及的是管理员账户,且仅限于那些在 “git hang” 问题之前就已存在的管理员账户,只需尝试再次登录即可触发。

随后,我检查了日志。现在我对 /logs 输出功能的工作原理更加熟悉,该功能非常出色!

此错误显示为“致命错误”,始于 22 日,且与 “git hang” 问题非常相似。但在此案例中,尽管进行了多次重建,该问题至今仍未解决,这意味着某些管理员账户实际上已被锁定。请参阅以下信息和回溯日志:

信息

Message

ActionView::Template::Error (no implicit conversion of Array into String)
app/serializers/current_user_serializer.rb:216:in 'CurrentUserSerializer#has_new_upcoming_changes'
lib/application_layout_preloader.rb:81:in 'ApplicationLayoutPreloader#preload_current_user_data'
lib/application_layout_preloader.rb:32:in 'ApplicationLayoutPreloader#preloaded_data'
app/helpers/application_helper.rb:987:in 'ApplicationHelper#preloaded_json'
app/views/layouts/application.html.erb:111
lib/topic_list_responder.rb:16:in 'block (2 levels) in TopicListResponder#respond_with_list'
lib/topic_list_responder.rb:7:in 'TopicListResponder#respond_with_list'
app/controllers/list_controller.rb:119:in 'block (2 levels) in class:ListController'
app/controllers/application_controller.rb:458:in 'block in ApplicationController#with_resolved_locale'
app/controllers/application_controller.rb:458:in 'ApplicationController#with_resolved_locale'
app/controllers/application_controller.rb:1140:in 'ApplicationController#ensure_dont_cache_page'
lib/middleware/omniauth_bypass_middleware.rb:35:in 'Middleware::OmniauthBypassMiddleware#call'
lib/middleware/crawler_hooks.rb:13:in 'Middleware::CrawlerHooks#call'
lib/content_security_policy/middleware.rb:12:in 'ContentSecurityPolicy::Middleware#call'
lib/middleware/anonymous_cache.rb:431:in 'Middleware::AnonymousCache#call'
lib/middleware/csp_script_nonce_injector.rb:13:in 'Middleware::CspScriptNonceInjector#call'
lib/middleware/track_view_session_id_injector.rb:12:in 'Middleware::TrackViewSessionIdInjector#call'
config/initializers/008-rack-cors.rb:14:in 'Discourse::Cors#call'
lib/middleware/default_headers.rb:13:in 'Middleware::DefaultHeaders#call'
config/initializers/100-quiet_logger.rb:20:in 'DiscourseRackQuietAssetsLogger#call'
config/initializers/100-silence_logger.rb:29:in 'SilenceLogger#call'
lib/middleware/enforce_hostname.rb:23:in 'Middleware::EnforceHostname#call'
lib/middleware/request_tracker.rb:384:in 'Middleware::RequestTracker#call'
lib/middlewar...

回溯:


Backtrace

activesupport (8.1.4) lib/active_support/values/time_zone.rb:461:in 'Date._parse'
activesupport (8.1.4) lib/active_support/values/time_zone.rb:461:in 'ActiveSupport::TimeZone#parse'
app/serializers/current_user_serializer.rb:216:in 'CurrentUserSerializer#has_new_upcoming_changes'
(eval at active_model_serializers-0.8.4/lib/active_model/serializer.rb:467):81:in 'CurrentUserSerializer#_fast_attributes'
active_model_serializers (0.8.4) lib/active_model/serializer.rb:456:in 'ActiveModel::Serializer#attributes'
active_model_serializers (0.8.4) lib/active_model/serializer.rb:480:in 'ActiveModel::Serializer#_serializable_hash'
active_model_serializers (0.8.4) lib/active_model/serializer.rb:359:in 'ActiveModel::Serializer#serializable_hash'
active_model_serializers (0.8.4) lib/active_model/serializer.rb:347:in 'ActiveModel::Serializer#as_json'
activesupport (8.1.4) lib/active_support/json/encoding.rb:53:in 'Oj::Rails::Encoder#encode'
activesupport (8.1.4) lib/active_support/json/encoding.rb:53:in 'ActiveSupport::JSON.encode'
activesupport (8.1.4) lib/active_support/core_ext/object/json.rb:42:in 'ActiveSupport::ToJsonWithActiveSupportEncoder#to_json'
active_model_serializers (0.8.4) lib/active_model/serializer.rb:331:in 'ActiveModel::Serializer#to_json'
multi_json (1.21.1) lib/multi_json/adapters/oj.rb:67:in 'Oj.dump'
multi_json (1.21.1) lib/multi_json/adapters/oj.rb:67:in 'MultiJSON::Adapters::Oj#dump'
multi_json (1.21.1) lib/multi_json/adapter.rb:110:in 'MultiJSON::Adapter.dump'
multi_json (1.21.1) lib/multi_json.rb:215:in 'MultiJSON.generate'
multi_json (1.21.1) lib/multi_json/deprecated.rb:34:in 'Kernel#public_send'
multi_json (1.21.1) lib/multi_json/deprecated.rb:34:in 'block in MultiJSON.deprecate_alias'
multi_json (1.21.1) lib/multi_json.rb:298:in 'Kernel#public_send'
multi_json (1.21.1) lib/multi_json.rb:298:in 'block (2 levels) in module:MultiJson'
lib/application_layout_preloader.rb:81:in 'ApplicationLayoutPreloader#preload_current_user_data'
lib/application_layout_preloader.rb:32:in 'ApplicationLayoutPreloader#preloaded_data'
app/helpers/application_helper.rb:987:in 'ApplicationHelper#preloaded_json'
app/views/layouts/application.html.erb:111
actionview (8.1.4) lib/action_view/base.rb:281:in 'Kernel#public_send'
actionview (8.1.4) lib/action_view/base.rb:281:in 'ActionView::Base#_run'
actionview (8.1.4) lib/action_view/template.rb:284:in 'block in ActionView::Template#render'
activesupport (8.1.4) lib/active_support/notifications.rb:212:in 'ActiveSupport::Notifications.instrument'
actionview (8.1.4) lib/action_view/template.rb:590:in 'ActionView::Template#instrument_render_template'
actionview (8.1.4) lib/action_view/template.rb:272:in 'ActionView::Template#render'
rack-mini-profiler (5.0.0) lib/mini_profiler/profiling_methods.rb:90:in 'block in ActionView::Template#profile_method'
actionview (8.1.4) lib/action_view/renderer/template_renderer.rb:77:in 'block in ActionView::TemplateRenderer#render_with_layout'
activesupport (8.1.4) lib/active_support/notifications.rb:210:in 'block in ActiveSupport::Notifications.instrument'
activesupport (8.1.4) lib/active_support/notifications/instrumenter.rb:58:in 'ActiveSupport::Notifications::Instrumenter#instrument'
activesupport (8.1.4) lib/active_support/notifications.rb:210:in 'ActiveSupport::Notifications.instrument'
actionview (8.1.4) lib/action_view/renderer/template_renderer.rb:75:in 'ActionView::TemplateRenderer#render_with_layout'
actionview (8.1.4) lib/action_view/renderer/template_renderer.rb:59:in 'ActionView::TemplateRenderer#render_template'
actionview (8.1.4) lib/action_view/renderer/template_renderer.rb:11:in 'ActionView::TemplateRenderer#render'
actionview (8.1.4) lib/action_view/renderer/renderer.rb:58:in 'ActionView::Renderer#render_template_to_object'
actionview (8.1.4) lib/action_view/renderer/renderer.rb:31:in 'ActionView::Renderer#render_to_object'
actionview (8.1.4) lib/action_view/rendering.rb:136:in 'block in ActionView::Rendering#_render_template'
actionview (8.1.4) lib/action_view/base.rb:308:in 'ActionView::Base#in_rendering_context'
actionview (8.1.4) lib/action_view/rendering.rb:135:in 'ActionView::Rendering#_render_template'
actionpack (8.1.4) lib/action_controller/metal/streaming.rb:179:in 'ActionController::Streaming#_render_template'
actionview (8.1.4) lib/action_view/rendering.rb:122:in 'ActionView::Rendering#render_to_body'
actionpack (8.1.4) lib/action_controller/metal/rendering.rb:192:in 'ActionController::Rendering#render_to_body'
actionpack (8.1.4) lib/action_controller/metal/renderers.rb:155:in 'ActionController::Renderers#render_to_body'
actionpack (8.1.4) lib/abstract_controller/rendering.rb:28:in 'AbstractController::Rendering#render'
actionpack (8.1.4) lib/action_controller/metal/rendering.rb:173:in 'ActionController::Rendering#render'
actionpack (8.1.4) lib/action_controller/metal/instrumentation.rb:31:in 'block (2 levels) in ActionController::Instrumentation#render'
activesupport (8.1.4) lib/active_support/benchmark.rb:17:in 'ActiveSupport::Benchmark.realtime'
actionpack (8.1.4) lib/action_controller/metal/instrumentation.rb:31:in 'block in ActionController::Instrumentation#render'
actionpack (8.1.4) lib/action_controller/metal/instrumentation.rb:100:in 'ActionController::Instrumentation#cleanup_view_runtime'
activerecord (8.1.4) lib/active_record/railties/controller_runtime.rb:48:in 'ActiveRecord::Railties::ControllerRuntime#cleanup_view_runtime'
actionpack (8.1.4) lib/action_controller/metal/instrumentation.rb:30:in 'ActionController::Instrumentation#render'
lib/topic_list_responder.rb:16:in 'block (2 levels) in TopicListResponder#respond_with_list'
actionpack (8.1.4) lib/action_controller/metal/mime_responds.rb:224:in 'ActionController::MimeResponds#respond_to'
lib/topic_list_responder.rb:7:in 'TopicListResponder#respond_with_list'
app/controllers/list_controller.rb:119:in 'block (2 levels) in class:ListController'
actionpack (8.1.4) lib/action_controller/metal/basic_implicit_render.rb:8:in 'ActionController::BasicImplicitRender#send_action'
actionpack (8.1.4) lib/abstract_controller/base.rb:221:in 'AbstractController::Base#process_action'
actionpack (8.1.4) lib/action_controller/metal/rendering.rb:199:in 'ActionController::Rendering#process_action'
actionpack (8.1.4) lib/abstract_controller/callbacks.rb:267:in 'block in AbstractController::Callbacks#process_action'
activesupport (8.1.4) lib/active_support/callbacks.rb:121:in 'block in ActiveSupport::Callbacks#run_callbacks'
app/controllers/application_controller.rb:458:in 'block in ApplicationController#with_resolved_locale'
i18n (1.14.8) lib/i18n.rb:354:in 'I18n::Base#with_locale'
app/controllers/application_controller.rb:458:in 'ApplicationController#with_resolved_locale'
activesupport (8.1.4) lib/active_support/callbacks.rb:130:in 'block in ActiveSupport::Callbacks#run_callbacks'
app/controllers/application_controller.rb:1140:in 'ApplicationController#ensure_dont_cache_page'
activesupport (8.1.4) lib/active_support/callbacks.rb:130:in 'block in ActiveSupport::Callbacks#run_callbacks'
activesupport (8.1.4) lib/active_support/callbacks.rb:141:in 'ActiveSupport::Callbacks#run_callbacks'
actionpack (8.1.4) lib/abstract_controller/callbacks.rb:266:in 'AbstractController::Callbacks#process_action'
actionpack (8.1.4) lib/action_controller/metal/rescue.rb:36:in 'ActionController::Rescue#process_action'
actionpack (8.1.4) lib/action_controller/metal/instrumentation.rb:76:in 'block in ActionController::Instrumentation#process_action'
activesupport (8.1.4) lib/active_support/notifications.rb:210:in 'block in ActiveSupport::Notifications.instrument'
activesupport (8.1.4) lib/ac

对于处于类似困境的人,这里有一个有效的临时解决方案,它允许管理员访问 discourse 实例:通过 ./launcher enter app 进入应用后,使用 rake create:admin 命令创建一个新的管理员用户账户。

然而,这并不能从根本上解决当前的问题,现有的管理员账户在登录时仍然会遇到 Oops 错误页面,无法像往常一样正常登录。

希望未来能有一个针对此问题的修复方案,提前感谢任何见解或建议。


可能相关的主题:

为了尝试用标准的 Discourse 功能来“出奇制胜”地解决问题,我琢磨着“合并”用户账号是否可行。比如,先创建一个新的管理员用户账号,然后将其合并到旧的管理员用户账号中(对于工作人员来说,这需要通过控制台操作)。

另一个想法是撤销然后重新授予管理员权限,但我不确定撤销权限是否会导致问题。

这算是我的一种“灵光一闪”的想法。我还没有尝试过上述任何操作,但我确实尝试过发布一个主题,然后将所有权更改给那个因错误而被锁定的管理员用户账号,随后这个 Discourse 的 post-notice new-user 通知弹出了以下内容:

:tada: 这是 [用户名] 第一次发帖——让我们欢迎他们加入网站吧!

天哪,就好像在这个(更改所有权)帖子之前,该管理员用户根本不存在一样。

这可能暗示了什么问题吗?:thinking:

我当时没有太注意,因为它们只是“警告”,但同时出现了一个 MaxMindDB 错误,且该错误发生在上述 ActiveVIEW::Tempalte::Error 之前。

MaxMindDB (/var/www/discourse/vendor/data/GeoLite2-City.mmdb) could not be found: No such file or directory @ rb_sysopen - /var/www/discourse/vendor/data/GeoLite2-City.mmdb
MaxMindDB (/var/www/discourse/vendor/data/GeoLite2-ASN.mmdb) could not be found: No such file or directory @ rb_sysopen - /var/www/discourse/vendor/data/GeoLite2-ASN.mmdb

我在 ENV 选项卡中发现了

Jobs::SuspiciousLogin

也许这个非致命的 MaxMindDB 错误(即警告)正在阻止管理员用户账户的登录,并出于某种原因或作为此处 bug 的一部分而显示 Oops 页面?

这是不是一个手动配置错误的 MaxMind 问题?

Maxmind 文件的访问在某些地区被屏蔽。我特别注意到在中国存在这种情况。

谢谢,不过这个 Discourse 服务器既不在中国,尝试登录的管理员用户所在地也不是中国,而且我认为 MaxMindDB 从未被配置过,或者即使部分配置了也从未完成。

我隐约记得管理后台里有 MaxMindDB 的设置,但现在我找不到任何相关内容。

我还刚刚意识到一件事,你必须以管理员身份登录才能查看 /logs,所以那位管理员用户可以看到日志,并且可以通过“返回站点”链接导航到 /admin,但随后却遇到了脉冲状的 UFO 光球(5 个蓝色圆圈),所以至少已经越过了 Oops 页面,虽然过程有些迂回,但仍然没有成功进入。:thinking:

我在日志中看到,这种迂回的活动正在产生更多 OP 提到的错误。

ActionView::Template::Error (no implicit conversion of Array into String)

呼叫是从服务器发出的,拨入位置无关紧要——值得检查一下

好的,但服务器并不在中国。

那只是一个例子。

哦,对,当然……哎呀!:grin: 只是不确定在这种情况下我应该检查什么。

@merefield @Ed_S @Falco 我能找到的与此错误相似的唯一实例在这里 Error "no implicit conversion of Array into String" when using Gemini AI analysis on posts with images 也许我应该把这个话题发到 Contribute > Bug 版块?

看起来这跟展示即将推出的变更有关——只有管理员才能看到。根据 ask.discourse.com 的说法:

整个功能由一个名为 enable_upcoming_changes 的隐藏站点设置控制,需在 Rails 控制台中将其设置为 false:

SiteSetting.enable_upcoming_changes = false

不过,这需要终端/服务器访问权限,因此只能在自托管安装环境中执行。

谢谢,我在 Rails 控制台中运行了该命令,但它提示“找不到命令” :thinking:

好的,抱歉,原来是 LLM 给了我过时的信息。

以下是我尝试过并使用的一些命令。

将管理员用户及其针对即将进行的更改的设置值制表如下:

# docker exec -it app rails r 'User.where(admin: true).each { |u| puts "#{u.id} #{u.username} #{u.user_option.enable_upcoming_change_available_notifications}" }'
-1 system true
-2 discobot true
1 AdminTeam false

针对给定的 ID(在我的情况下是 1),切换该 ID 的设置:

# docker exec -it app rails r 'x=1;User.find(x).user_option.update!(enable_upcoming_change_available_notifications: !User.find(x).user_option.enable_upcoming_change_available_notifications)'

我当然更倾向于从 root shell 中执行的一行命令。当然,如果愿意的话,也可以进入 docker,再进入 rails,然后执行操作。

我每次都会感到有点迷失方向,所以你说的root shell是指通过 ./launcher enter app 进入,然后运行 rails c 吗?

好的,输出如下:

-1 system true

没有列出任何旧管理员或新管理员,也没有 discobot 或其他任何人。

也许问题就在这里,需要针对相关管理员用户启用/应用该设置。如果是这样,如何找到其 ID?

好的,我再次运行了命令,找到了 id,它是 1,所以设置是一样的。

但是,当我输入以下内容并运行时,它显示的是 => true

x=1;User.find(x).user_option.update!(enable_upcoming_change_available_notifications: !User.find(x).user_option.enable_upcoming_change_available_notifications)

我们希望它是 false,对吧?所以我看不出该命令中应该更改什么。我将该操作理解为“查找”,没有其他含义,这就是 => true 的输出,而这显然没有针对目标用户生效。

我想我本应该采用更简单的方案……

# docker exec -it app rails r 'x=1;User.find(x).user_option.update!(enable_upcoming_change_available_notifications: false)'

以及类似的操作。我不确定为什么当时没想到这样做。

我在应用里和 rails c 中粘贴了那段代码,输出结果是

=> true

但我检查后发现,在表格化的输出中它确实变成了 false。

我试了登录,但还是遇到 Oops 错误,也许我需要重新构建一下?

让我回溯一下……我当时在那里做的,是尝试修改管理员偏好设置,希望抛出异常的代码不需要执行。

但我们真正想弄清楚的是,是否存在需要修复的代码 bug,或者数据库中是否存在本不该出现的异常数据。当然,两者兼有也是可能的。

回溯日志指向 app/serializers/current_user_serializer.rb 中的这段代码

  def has_new_upcoming_changes
    last_visited = object.custom_fields["last_visited_upcoming_changes_at"]
    return false if last_visited.blank? && object.created_at < Discourse.site_creation_date + 1.hour
    cutoff = last_visited.present? ? Time.zone.parse(last_visited) : object.created_at
    UpcomingChangeEvent.added.not_backfilled.where("created_at > ?", cutoff).exists?
  end

可以运行一个数据浏览器查询,以查看您的管理员账户中 last_visited_upcoming_changes_at 的值是什么。

SELECT 
    ucf.id AS custom_field_id, 
    ucf.user_id, 
    u.username,
    ucf.name, 
    ucf.value 
FROM user_custom_fields ucf
INNER JOIN users u ON u.id = ucf.user_id
WHERE ucf.name = 'last_visited_upcoming_changes_at'
  AND u.admin = true

这可能会有所帮助。在我的情况下(最近更新到了 v2026.7.3),它只是一个日期字符串,我认为它应该就是这样。

谢谢你的回复。现在返回了两个自定义字段,都是针对同一个旧的管理员用户,但两条记录的时间值完全相同:

| last_visited_upcoming_changes_at | 2026-09-22T10:30:47Z |
| last_visited_upcoming_changes_at | 2026-09-22T10:30:47Z |

相比之下,新的管理员账户显示了一个更近的时间戳,并且该用户只有一个自定义字段条目:

| last_visited_upcoming_changes_at | 2026-10-02T08:23:22Z |


当前 Discourse 版本:2026.10.0-latest