Devise::MissingWarden Error Using Turbo Stream Broadcasts in Ruby on Rails
1 May 2026
In September 2025, our development team at Sentia built a real-time messaging system between different users for an existing client project. When testing this system on our staging environment, I ran into the issue below:
Devise::MissingWardenDevise could not find the `Warden::Proxy` instance on your request environment. (Devise::MissingWarden) Make sure that your application is loading Devise and Warden as expected and that the `Warden::Manager` middleware is present in your middleware stack. If you are seeing this on one of your tests, ensure that your tests are either executing the Rails middleware stack or that your tests are using the `Devise::Test::ControllerHelpers` module to inject the `request.env['warden']` object for you.
Reading the error message, my first thought was there may be something wrong with how we setup Devise authentication or how the Devise gem interacts with the new messaging system we implemented.
Puzzled, I began searching for answers online and came across this useful forum discussion thread from Hotwire, the team responsible behind Stimulus and Turbo,
According to David Heinemeier Hansson (more commonly known as DHH), the creator of the Ruby on Rails framework:
Partials used for turbo streaming have to be free of global references, as they’re rendered by the ApplicationRenderer, not within the context of a specific request.
In our case, instead of partials, we were using view components instead but the same principle applies.
When building our messaging system between multiple parties, we needed to keep track of the current user because our chat components are displayed differently depending on which user type was viewing the message.
In Devise, we can track who is viewing the message component by using the current_user global variable, but as DHH says, we do not have access to the context of the request, meaning Warden session variables such as current_user are not available.
I have attached some simplified snippet of the code causing the issues.
Here, we have our chat preview UI component that displays differently depending on who is viewing it. By using current_user, we get the appropriate UI updates based on who is viewing the chat. In this example, which is a chat involving 2 people, User 1 would see the chat name as User 2's business name. User 2 would see the chat name as User 1's business name.
class ChatPreviewComponent < ViewComponent::Base
def initialize(chat:, message:)
@chat = chat
@message = message
end
def chat_name
@chat.other_user(current_user)&.current_business&.name || "Unknown"
end
We have a ChatListComponent that has many ChatPreviewComponents.
class ChatListComponent < ViewComponent::Base
renders_many :chat_previews, "Bookings::ChatPreviewComponent"
def initialize(chats:, message:)
@chats = chats
@message = message
end
We use the ApplicationController to render the HTML and then use Turbo Stream broadcasts to update the contents of the chat message to the user in real-time.
component = Bookings::ChatListComponent.new(
chats: chats,
current_user: current_user,
message: @chat_message
)
html = ApplicationController.render(component, layout: false)
@chat_message.broadcast_replace_later_to(
[ participant.id, "chat" ],
target: "chat-list-#{participant.id}",
html: html
)
To fix our issue, instead of relying on current_user to update the UI correctly for each different user in the chat, I made sure to just directly pass in the relevant user to the chat UI components instead. Since we need to broadcast the chat UI change to all parties involved in the chat, I just iterate through all participants in the chat and pass it to the ChatListComponent like below.
def participants
@chat_thread.booking_participants
end
def call
participants.each do |participant|
broadcast_chat_list_to_participant(participant)
end
end
def broadcast_chat_list_to_participant(participant)
component = Bookings::ChatListComponent.new(
chats: chats,
current_user: participant,
message: @chat_message
)
html = ApplicationController.render(component, layout: false)
@chat_message.broadcast_replace_later_to(
[ participant.id, "chat" ],
target: "chat-list-#{participant.id}",
html: html
)
This allows us to still get the dynamic UI based on who is viewing the chat without using the global variable provided by Devise.
We repeated similar changes for other message UI components, passing in the User object as an argument when initialising the ViewComponent or through locals when using partials.
I hope this helps out any other developers facing a similar issue and thanks for reading this post!