Issue Description
Sentry's Faraday integration calls builder.insert from every Faraday::Connection#initialize for non-Net::HTTP adapters.
Some clients reuse one Faraday::RackBuilder across multiple connections. After the first request locks that builder, constructing another connection causes Sentry to attempt a second insertion and raise Faraday::RackBuilder::StackLocked.
We encountered this with Ably Ruby, which reuses one builder for its primary and fallback connections. When the primary request fails, Ably constructs a fallback connection using the same builder. Sentry raises while that connection is being initialized, before the fallback request can be attempted. The exception escapes into the application and interrupts Ably's normal fallback handling.
Reproduction Steps
With sentry-ruby 7.0.0 and Faraday 1.10.6 installed, run:
require "faraday"
require "sentry-ruby"
Sentry.init do |config|
config.dsn = nil
config.enabled_patches = [:faraday]
end
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
stub.get("/") { [200, {}, "ok"] }
end
builder = Faraday::RackBuilder.new do |connection|
connection.adapter :test, stubs
end
primary = Faraday.new("https://primary.example", builder: builder)
primary.get("/")
Faraday.new("https://fallback.example", builder: builder)
The test adapter keeps the reproduction network-free. Calling primary.get causes Faraday to lock the builder in the same way as a normal request.
Expected Behavior
Constructing another connection with a builder already instrumented by Sentry should succeed without attempting to modify that builder again.
Could Sentry make the Faraday middleware insertion idempotent for each builder? In this case, Sentry inserted its instrumentation before the builder was locked, so the next connection could detect that the same builder has already been instrumented and skip the second builder.insert.
Disabling the :faraday patch avoids the exception, but also removes outbound tracing for Faraday clients using non-Net::HTTP adapters.
Actual Behavior
The final Faraday.new raises:
Faraday::RackBuilder::StackLocked:
can't modify middleware stack after making a request
faraday/rack_builder.rb:221:in `raise_if_locked'
faraday/rack_builder.rb:121:in `insert'
sentry-ruby/lib/sentry/faraday.rb:20:in `initialize'
The same reproduction constructs the second connection successfully when Sentry's :faraday patch is disabled.
Ruby Version
4.0.2
SDK Version
7.0.0
Integration and Its Version
- Faraday 1.10.6
- Ably 1.2.0 in the original application
- Typhoeus adapter in the original application
The minimal reproduction uses Faraday's test adapter.
Sentry Config
Sentry.init do |config|
config.enabled_patches = [:faraday]
end
Issue Description
Sentry's Faraday integration calls
builder.insertfrom everyFaraday::Connection#initializefor non-Net::HTTP adapters.Some clients reuse one
Faraday::RackBuilderacross multiple connections. After the first request locks that builder, constructing another connection causes Sentry to attempt a second insertion and raiseFaraday::RackBuilder::StackLocked.We encountered this with Ably Ruby, which reuses one builder for its primary and fallback connections. When the primary request fails, Ably constructs a fallback connection using the same builder. Sentry raises while that connection is being initialized, before the fallback request can be attempted. The exception escapes into the application and interrupts Ably's normal fallback handling.
Reproduction Steps
With
sentry-ruby7.0.0 and Faraday 1.10.6 installed, run:The test adapter keeps the reproduction network-free. Calling
primary.getcauses Faraday to lock the builder in the same way as a normal request.Expected Behavior
Constructing another connection with a builder already instrumented by Sentry should succeed without attempting to modify that builder again.
Could Sentry make the Faraday middleware insertion idempotent for each builder? In this case, Sentry inserted its instrumentation before the builder was locked, so the next connection could detect that the same builder has already been instrumented and skip the second
builder.insert.Disabling the
:faradaypatch avoids the exception, but also removes outbound tracing for Faraday clients using non-Net::HTTP adapters.Actual Behavior
The final
Faraday.newraises:The same reproduction constructs the second connection successfully when Sentry's
:faradaypatch is disabled.Ruby Version
4.0.2
SDK Version
7.0.0
Integration and Its Version
The minimal reproduction uses Faraday's test adapter.
Sentry Config