Skip to content

ActionCable instrumentation breaks all /cable connections on Rails 8.2 / main (private handle_open called publicly by Server::Socket) #2975

@kaushgem

Description

@kaushgem

Issue Description

sentry-rails instruments ActionCable by prepending Sentry::Rails::ActionCableExtensions::Connection onto the connection, and that module declares #handle_open / #handle_close as private (sentry-rails/lib/sentry/rails/action_cable.rb):

module Connection
  private

  def handle_open
    ErrorHandler.capture(self, transaction_name: "#{self.class.name}#connect") { super }
  end

  def handle_close
    ErrorHandler.capture(self, transaction_name: "#{self.class.name}#disconnect") { super }
  end
end

Rails 8.2 / main decoupled the cable socket from the connection (rails/rails#50979, merged 2026-05-28). ActionCable::Server::Socket now calls the connection back with an explicit receiver, which requires the method to be public:

def handle_open
  @protocol = websocket.protocol
  @connection.handle_open     # explicit receiver -> must be public
  message_buffer.process!
  server.add_connection(@connection)
end

Because the prepended module sits ahead of ActionCable::Connection::Base in the ancestor chain and marks the method private, every /cable upgrade raises NoMethodError. The WebSocket upgrade returns 101, but handle_open raises before welcome is sent, so clients never receive welcome/pings and reconnect-loop forever — no broadcasts (Turbo Streams, presence) are ever delivered. The exception only reaches the Rails logger, not Sentry, since it happens inside the instrumentation wrapper. In Rails' own Connection::Base, both methods are public; the prepended private versions invert the intended visibility.

Reproduction Steps

  1. Rails app tracking rails/rails main (any revision including the ActionCable::Server::Socket extraction; reproduced on 8.2.0.alpha).
  2. Add sentry-rails and configure Sentry.init.
  3. Open a WebSocket to /cable (e.g. a Turbo Stream subscription).
  4. The upgrade raises immediately:
NoMethodError: private method 'handle_open' called for an instance of ApplicationCable::Connection
  actioncable/lib/action_cable/server/socket.rb:127:in 'handle_open'

Expected Behavior

/cable WebSocket connections open normally with Sentry instrumentation active.

Actual Behavior

Every /cable upgrade raises NoMethodError (private method 'handle_open' called ...); the client never receives welcome and reconnect-loops; no broadcasts are delivered.

Ruby Version

4.0.1

SDK Version

sentry-rails 6.6.1 (also reproduces on the latest release 6.6.2 and current master — both still mark these private)

Integration and Its Version

Rails 8.2.0.alpha (rails/rails main, rev 324b65c2dffe17ee03522b39b516f482087f244f) — ActionCable

Sentry Config

Standard Sentry.init; no special config needed to trigger.

Workaround (until a fix ships)

Re-publicize the two methods in an initializer:

Sentry::Rails::ActionCableExtensions::Connection.send(:public, :handle_open, :handle_close)

Metadata

Metadata

Assignees

No fields configured for issues without a type.

Projects

Status
Waiting for: Product Owner

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions