current_user is a Hash in Rails 8.0.2
I upgraded from Rails 8.0.1 to 8.0.2. Noticed the following:
- If the user was already logged out when going to the app and tried to login, they are immediately bounced back to the login screen with no error message and no errors in the logs.
- If the user already had a live session when I deployed the app with the upgrade from 8.0.1 -> 8.0.2, every action got an error because current_user is coming through ApplicationController as a Hash, not an Object.
LMK if I can give any other information. Ruby 3.4.2 btw.
I have the same problem, appears sometimes in my test suite after rails upgrade.
This is what seems to work for me (config/initializers/devise.rb):
Warden::Manager.serialize_into_session do |user|
user.id
end
Warden::Manager.serialize_from_session do |id|
User.find(id)
end
Interesting. I'll have to check my config and make sure I'm not doing anything weird.
The only thing I've seen is that when running in the production environment, Warden doesn't find any authentication strategies in its config, but it does in development. Still searching.
I'm seeing the same thing -- Warden can't find valid mapping
- Rails 8.02
- Devise 4.9.4
Failure/Error: before { sign_in user }
RuntimeError:
Could not find a valid mapping for #<User id: 1, email: [FILTERED], first_name: "Milford", last_name: "Bergstrom", created_at: "2025-04-16 16:44:38.469535000 +0000", updated_at: "2025-04-16 16:44:38.469535000 +0000", organization_id: 1, role_id: 1>
# /usr/local/bundle/ruby/3.4.0/gems/devise-4.9.4/lib/devise/mapping.rb:46:in 'Devise::Mapping.find_scope!'
# /usr/local/bundle/ruby/3.4.0/gems/devise-4.9.4/lib/devise/test/integration_helpers.rb:38:in 'Devise::Test::IntegrationHelpers#sign_in'
# ./spec/requests/uploads_spec.rb:27:in 'block (4 levels) in <main>'
Adding
RSpec.configure do |config|
%i(request controller).each do |type|
config.before(:each, type: type) do
Rails.application.try(:reload_routes_unless_loaded)
end
end
config.before(:suite) do
Devise.configure_warden!
end
end
Warden::Manager.serialize_into_session do |user|
user.id
end
Warden::Manager.serialize_from_session do |id|
User.find(id)
end
To my rails_helper.rb fixes it for now.
So, I did figure something out. When I first upgraded to Rails 8.0.1 there was a bug which affected route loading. As a result, based on the conversation in #5716 , I changed config.reload_routes = false in config/initializers/devise.rb. Well after upgrading to 8.0.2 that configuration broke it. Merely commenting that out as it had been since I've started using Devise fixed this problem.
For me, https://github.com/heartcombo/devise/issues/5774#issuecomment-2803988684 is what fixes it (thank you! I spent all day trying to figure this out).
Commenting or showing config.reload_routes = false doesn't impact it.
We encountered intermittent test failures relating to this (in our case, current_admin returning a hash instead of an Admin instance).
A handy rspec --bisect narrowed it down to an RSpec controller block (controller { ... }) running before Rails routes are loaded. RSpec initializes a new RouteSet, triggering #draw and #finalize! before the main app’s routes have loaded. This configured Devise without any devise_for mappings from routes.rb.
Devise builds and caches "mappings" (e.g., for :admin) when devise_for is called in routes.rb. These mappings are used to configure Warden, including session serialization and deserialization.
Devise hooks into ActionDispatch::Routing::RouteSet#finalize! to register these mappings and configure Warden. Configuration can only happen once. If any code triggers #finalize! before Devise registers its mappings (e.g., due to test-specific routing), the Warden configuration is incomplete.
For us, the fix was to explicitly eager load the application routes before the controller test, ensuring Devise mappings are registered before #finalize! is called.
I also tracked down the intermittent failure issue to mappings not being loaded yet. Even though Devise.mappings is trying to call the new lazy loaded routes, I found that adding Rails.application.try(:reload_routes_unless_loaded) to a before block in rspec made the flaky tests go away
@mbaird thanks for the details in your last comment. It helped me track a similar issue when a gem used Rails::Engine where it called routes.draw, which caused same issue with Devise when eagerly loaded. Now I'm not sure whether the author of the gem made a mistake by declaring these routes too early, or simply this assumption from Devise devs that config/routes will be loaded first simply doesn't hold 🤔
Are you still running into issues with Devise main? I want to make sure that we're doing the right thing to fix these on Rails 8+. Thanks.