Issue Description
When using Rails.error.set_context to attach debugging context before raising an exception, the context never appears in Sentry events. This happens because Sentry's own exception capture (via CaptureExceptions middleware for web requests, or ActiveJobExtensions::SentryReporter for jobs) always runs before the exception reaches Rails.error.report, and Sentry's @__sentry_captured deduplication then discards the second capture that would have carried the context.
This makes Rails.error.set_context effectively useless for anyone using register_error_subscriber = true — the subscriber receives the context correctly, but by the time it calls capture_exception, the exception is already marked as captured and gets silently skipped.
Workaround
We are using a global event processor in our Sentry initializer that reads ActiveSupport::ExecutionContext directly in the calling thread before Sentry dispatches to its background worker:
Sentry::Scope.add_global_event_processor do |event, _hint|
rails_context = ActiveSupport::ExecutionContext.to_h
if rails_context.present?
safe_context = rails_context.transform_values do |value|
case value
when String, Numeric, Symbol, NilClass, TrueClass, FalseClass
value
else
value.class.name
end
end
event.contexts["rails.error"] = (event.contexts["rails.error"] || {}).merge(safe_context)
end
event
end
This works because event processors run synchronously in the calling thread (where ExecutionContext is still populated) before the event is handed off to Sentry's background worker. We filter non-primitive values to avoid leaking sensitive data from objects like ActiveRecord models.
Reproduction Steps
-
Configure Sentry with config.rails.register_error_subscriber = true
-
In any controller action or ActiveJob, set context and raise:
Rails.error.set_context(debug_key: "important_value")
raise StandardError, "something went wrong"
- Check the resulting Sentry event — the
debug_key context is missing.
Root cause — two paths, both broken
ActiveJob path: SentryReporter.record wraps perform_now with rescue Exception => e and calls capture_exception directly. ActiveJob's execution chain (ActiveJob::Execution#_perform_job) has no Rails.error.record wrapper, so Rails.error.report is never called. The ErrorSubscriber never runs at all.
Web request path (production): The exception propagates upward through:
RescuedExceptionInterceptor → re-raises
DebugExceptions → logs, re-raises (production, show_detailed_exceptions is false)
CaptureExceptions → catches, calls Sentry::Rails.capture_exception (sets @__sentry_captured = true), re-raises
ShowExceptions → catches, renders error page, sets env["action_dispatch.report_exception"]
Executor → sees report_exception, calls Rails.error.report(error) → merges ActiveSupport::ExecutionContext.to_h (which has the set_context data) → dispatches to ErrorSubscriber
ErrorSubscriber#report → calls Sentry::Rails.capture_exception → Hub#capture_exception checks Sentry.exception_captured?(exception) → true → returns immediately, discarding the context
So for web requests, the context does reach the ErrorSubscriber, but the event is deduplicated away because CaptureExceptions already captured it in step 3.
Expected Behavior
Context set via Rails.error.set_context (stored in ActiveSupport::ExecutionContext) should appear in the Sentry event, either by:
- Having
CaptureExceptions and SentryReporter read ActiveSupport::ExecutionContext.to_h at capture time (e.g., merge into contexts["rails.error"]), or
- Reversing the capture priority so the
ErrorSubscriber path (which includes the context) is preferred, and CaptureExceptions/SentryReporter defer to it, or
- Some other approach that ensures the two systems don't silently discard each other's data
Actual Behavior
Context set via Rails.error.set_context never appears in Sentry events. Users expect that with register_error_subscriber = true, context set through the Rails error reporter API would be forwarded to Sentry. Instead, it is silently discarded in all cases.
Ruby Version
4.0.2
SDK Version
6.5.0
Integration and Its Version
Rails 8.1.3 (ActiveJob via GoodJob)
Sentry Config
Sentry.init do |config|
config.dsn = "..."
config.breadcrumbs_logger = [:active_support_logger, :http_logger]
config.enabled_patches << :faraday
config.rails.register_error_subscriber = true
config.traces_sampler = lambda { |ctx| ... } # custom sampling
end
Issue Description
When using
Rails.error.set_contextto attach debugging context before raising an exception, the context never appears in Sentry events. This happens because Sentry's own exception capture (viaCaptureExceptionsmiddleware for web requests, orActiveJobExtensions::SentryReporterfor jobs) always runs before the exception reachesRails.error.report, and Sentry's@__sentry_captureddeduplication then discards the second capture that would have carried the context.This makes
Rails.error.set_contexteffectively useless for anyone usingregister_error_subscriber = true— the subscriber receives the context correctly, but by the time it callscapture_exception, the exception is already marked as captured and gets silently skipped.Workaround
We are using a global event processor in our Sentry initializer that reads
ActiveSupport::ExecutionContextdirectly in the calling thread before Sentry dispatches to its background worker:This works because event processors run synchronously in the calling thread (where
ExecutionContextis still populated) before the event is handed off to Sentry's background worker. We filter non-primitive values to avoid leaking sensitive data from objects like ActiveRecord models.Reproduction Steps
Configure Sentry with
config.rails.register_error_subscriber = trueIn any controller action or ActiveJob, set context and raise:
debug_keycontext is missing.Root cause — two paths, both broken
ActiveJob path:
SentryReporter.recordwrapsperform_nowwithrescue Exception => eand callscapture_exceptiondirectly. ActiveJob's execution chain (ActiveJob::Execution#_perform_job) has noRails.error.recordwrapper, soRails.error.reportis never called. TheErrorSubscribernever runs at all.Web request path (production): The exception propagates upward through:
RescuedExceptionInterceptor→ re-raisesDebugExceptions→ logs, re-raises (production,show_detailed_exceptionsis false)CaptureExceptions→ catches, callsSentry::Rails.capture_exception(sets@__sentry_captured = true), re-raisesShowExceptions→ catches, renders error page, setsenv["action_dispatch.report_exception"]Executor→ seesreport_exception, callsRails.error.report(error)→ mergesActiveSupport::ExecutionContext.to_h(which has theset_contextdata) → dispatches toErrorSubscriberErrorSubscriber#report→ callsSentry::Rails.capture_exception→Hub#capture_exceptionchecksSentry.exception_captured?(exception)→ true → returns immediately, discarding the contextSo for web requests, the context does reach the
ErrorSubscriber, but the event is deduplicated away becauseCaptureExceptionsalready captured it in step 3.Expected Behavior
Context set via
Rails.error.set_context(stored inActiveSupport::ExecutionContext) should appear in the Sentry event, either by:CaptureExceptionsandSentryReporterreadActiveSupport::ExecutionContext.to_hat capture time (e.g., merge intocontexts["rails.error"]), orErrorSubscriberpath (which includes the context) is preferred, andCaptureExceptions/SentryReporterdefer to it, orActual Behavior
Context set via
Rails.error.set_contextnever appears in Sentry events. Users expect that withregister_error_subscriber = true, context set through the Rails error reporter API would be forwarded to Sentry. Instead, it is silently discarded in all cases.Ruby Version
4.0.2
SDK Version
6.5.0
Integration and Its Version
Rails 8.1.3 (ActiveJob via GoodJob)
Sentry Config